mirror of
https://gitee.com/liweiyi/ChestnutCMS.git
synced 2025-12-06 16:38:24 +08:00
版本更新:v1.5.1
This commit is contained in:
parent
29537b2388
commit
bd42862278
18
NOTICE
18
NOTICE
@ -13,15 +13,7 @@ Copyright 2002-2024 The Apache Software Foundation
|
||||
This product includes software developed at
|
||||
The Apache Software Foundation (https://www.apache.org/).
|
||||
-----------------------------------------------------------------------
|
||||
This product contains code from the redisson Project:
|
||||
|
||||
Apache Commons Text
|
||||
Copyright 2014-2024 The Apache Software Foundation
|
||||
|
||||
This product includes software developed at
|
||||
The Apache Software Foundation (https://www.apache.org/).
|
||||
-----------------------------------------------------------------------
|
||||
This product contains code from the redisson Project:
|
||||
This product contains code from the Apache Commons Text Project:
|
||||
|
||||
Apache Commons Text
|
||||
Copyright 2014-2024 The Apache Software Foundation
|
||||
@ -41,3 +33,11 @@ The files
|
||||
- velocity-engine-scripting/src/main/java/org/apache/velocity/script/VelocityScriptEngine.java
|
||||
- velocity-engine-scripting/src/main/java/org/apache/velocity/script/VelocityScriptEngineFactory.java
|
||||
are Copyright 2006 Sun Microsystems, Inc., and licenced under a BSD-like licence.
|
||||
-----------------------------------------------------------------------
|
||||
This product contains code from the flexmark-java Project:
|
||||
|
||||
Copyright (c) 2015-2016, Atlassian Pty Ltd
|
||||
All rights reserved.
|
||||
|
||||
Copyright (c) 2016-2018, Vladimir Schneider,
|
||||
All rights reserved.
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
# ChestnutCMS v1.5.0
|
||||
# ChestnutCMS v1.5.1
|
||||
|
||||
### 系统简介
|
||||
|
||||
@ -10,9 +10,9 @@ ChestnutCMS是前后端分离的企业级内容管理系统。项目基于[RuoYi
|
||||
|
||||
账号:demo / a123456
|
||||
|
||||
企业站演示地址:<http://swikoon.1000mz.com>
|
||||
企业站演示地址:<https://swikoon.1000mz.com>
|
||||
|
||||
资讯站演示地址:<http://news.1000mz.com>(会员演示账号:xxx333@126.com / a123456)
|
||||
资讯站演示地址:<https://news.1000mz.com>(会员演示账号:xxx333@126.com / a123456)
|
||||
|
||||
图片站演示地址:PC端:<http://tpz.1000mz.com> 移动端:<http://mtpz.1000mz.com>
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>chestnut</artifactId>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<version>1.5.0</version>
|
||||
<version>1.5.1</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
@ -5,7 +5,7 @@ chestnut:
|
||||
# 代号
|
||||
alias: ChestnutCMS
|
||||
# 版本
|
||||
version: 1.5.0
|
||||
version: 1.5.1
|
||||
# 版权年份
|
||||
copyrightYear: 2022-2024
|
||||
system:
|
||||
@ -191,10 +191,8 @@ spring:
|
||||
|
||||
# Actuator 监控端点的配置项
|
||||
management:
|
||||
trace:
|
||||
http:
|
||||
enabled: true
|
||||
endpoints:
|
||||
enabled-by-default: false
|
||||
web:
|
||||
exposure:
|
||||
include: '*'
|
||||
@ -203,6 +201,9 @@ management:
|
||||
show-details: ALWAYS
|
||||
logfile:
|
||||
external-file: ./logs/client.log
|
||||
httpexchanges:
|
||||
recording:
|
||||
enabled: true
|
||||
|
||||
sa-token:
|
||||
# token名称 (同时也是cookie名称)
|
||||
@ -237,6 +238,9 @@ mybatis-plus:
|
||||
xss:
|
||||
# 过滤开关
|
||||
enabled: true
|
||||
# 过滤链接
|
||||
urlPatterns:
|
||||
- /*
|
||||
|
||||
xxl:
|
||||
job:
|
||||
|
||||
@ -5,7 +5,7 @@ chestnut:
|
||||
# 代号
|
||||
alias: ChestnutCMS
|
||||
# 版本
|
||||
version: 1.5.0
|
||||
version: 1.5.1
|
||||
# 版权年份
|
||||
copyrightYear: 2022-2024
|
||||
system:
|
||||
@ -195,7 +195,7 @@ sa-token:
|
||||
# token有效期,单位s 默认30天, -1代表永不过期
|
||||
timeout: 2592000
|
||||
# token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒
|
||||
active-timeout: -1
|
||||
active-timeout: 1800
|
||||
# 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
|
||||
is-concurrent: true
|
||||
# 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
|
||||
|
||||
@ -1,222 +1,222 @@
|
||||
# 项目相关配置
|
||||
chestnut:
|
||||
# 名称
|
||||
name: 栗子内容管理系统
|
||||
# 代号
|
||||
alias: ChestnutCMS
|
||||
# 版本
|
||||
version: 1.5.0
|
||||
# 版权年份
|
||||
copyrightYear: 2022-2024
|
||||
system:
|
||||
# 演示模式开关
|
||||
demoMode: true
|
||||
# 文件路径 示例( Windows配置D:/chestnut/uploadPath,Linux配置 /home/app/uploadPath)
|
||||
uploadPath: /home/app/uploadPath
|
||||
# 验证码类型 math 数组计算 char 字符验证
|
||||
captchaType: math
|
||||
freemarker:
|
||||
templateLoaderPath: /home/app/statics
|
||||
cms:
|
||||
resourceRoot: /home/app/wwwroot_release
|
||||
|
||||
# 开发环境配置
|
||||
server:
|
||||
# 服务器的HTTP端口,默认为8090
|
||||
port: 8090
|
||||
servlet:
|
||||
# 应用的访问路径
|
||||
context-path: /
|
||||
tomcat:
|
||||
# tomcat的URI编码
|
||||
uri-encoding: UTF-8
|
||||
# 连接数满后的排队数,默认为100
|
||||
accept-count: 1000
|
||||
threads:
|
||||
# tomcat最大线程数,默认为200
|
||||
max: 800
|
||||
# Tomcat启动初始化的线程数,默认值10
|
||||
min-spare: 100
|
||||
|
||||
# 日志配置
|
||||
logging:
|
||||
level:
|
||||
com.chestnut: debug
|
||||
org.springframework: warn
|
||||
|
||||
# Spring配置
|
||||
spring:
|
||||
# 资源信息
|
||||
messages:
|
||||
# 国际化资源文件路径
|
||||
basename: i18n/messages
|
||||
# 文件上传
|
||||
servlet:
|
||||
multipart:
|
||||
# 单个文件大小
|
||||
max-file-size: 20MB
|
||||
# 设置总上传的文件大小
|
||||
max-request-size: 100MB
|
||||
# 服务模块
|
||||
devtools:
|
||||
restart:
|
||||
# 热部署开关
|
||||
enabled: false
|
||||
freemarker:
|
||||
check-template-location: false
|
||||
elasticsearch:
|
||||
uris: http://cc-elasticsearch:9200
|
||||
username: elastic
|
||||
password: hello1234
|
||||
# redis 配置
|
||||
data:
|
||||
redis:
|
||||
# 地址
|
||||
host: cc-redis
|
||||
# 端口,默认为6379
|
||||
port: 6379
|
||||
# 数据库索引
|
||||
database: 0
|
||||
# 密码
|
||||
password: b18a03
|
||||
# 连接超时时间
|
||||
timeout: 10s
|
||||
lettuce:
|
||||
pool:
|
||||
# 连接池中的最小空闲连接
|
||||
min-idle: 0
|
||||
# 连接池中的最大空闲连接
|
||||
max-idle: 8
|
||||
# 连接池的最大数据库连接数
|
||||
max-active: 8
|
||||
# #连接池最大阻塞等待时间(使用负值表示没有限制)
|
||||
max-wait: -1ms
|
||||
flyway:
|
||||
enabled: false
|
||||
# 迁移sql脚本文件存放路径,默认:classpath:db/migration
|
||||
locations: classpath:db/migration/mysql
|
||||
# 迁移sql脚本文件名称的前缀,默认:V
|
||||
sql-migration-prefix: V
|
||||
# 迁移sql脚本文件名称分隔符,默认2个下划线:__
|
||||
sql-migration-separator: __
|
||||
# 迁移sql脚本文件名称后缀
|
||||
sql-migration-suffixes: .sql
|
||||
# 迁移时是否进行校验
|
||||
validate-on-migrate: true
|
||||
# 当迁移发现数据库非空且存在没有元数据的表时,自动执行基准迁移,新建schema_version表
|
||||
baseline-on-migrate: true
|
||||
# 数据库配置
|
||||
datasource:
|
||||
# type: com.alibaba.druid.pool.DruidDataSource
|
||||
type: com.zaxxer.hikari.HikariDataSource
|
||||
dynamic:
|
||||
primary: master
|
||||
# 严格模式 匹配不到数据源则报错
|
||||
strict: true
|
||||
# 主库
|
||||
datasource:
|
||||
master:
|
||||
type: ${spring.datasource.type}
|
||||
driverClassName: com.mysql.cj.jdbc.Driver
|
||||
url: jdbc:mysql://127.0.0.1:3308/chestnut_cms?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
|
||||
username: root
|
||||
password: hello1234
|
||||
# 从库
|
||||
#slave:
|
||||
# lazy: true
|
||||
# type: ${spring.datasource.type}
|
||||
# driverClassName: com.mysql.cj.jdbc.Driver
|
||||
# url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
|
||||
# username:
|
||||
# password:
|
||||
hikari:
|
||||
# 连接池名
|
||||
pool-name: HikariCP
|
||||
# 连接超时时间:毫秒, 默认30秒
|
||||
connection-timeout: 2000
|
||||
# 最小空闲连接,默认值10,小于0或大于maximum-pool-size,都会重置为maximum-pool-size
|
||||
minimum-idle: 5
|
||||
# 最大连接数,小于等于0会被重置为默认值10;大于零小于1会被重置为minimum-idle的值
|
||||
maximum-pool-size: 20
|
||||
# 空闲连接最大存活时间,默认值600000(10分钟),大于等于max-lifetime且max-lifetime>0,会被重置为0;不等于0且小于10秒,会被重置为10秒。
|
||||
idle-timeout: 200000
|
||||
# 连接池返回的连接默认自动提交,默认只 true
|
||||
auto-commit: true
|
||||
# 连接最大存活时间,不等于0且小于30秒,会被重置为默认值30分钟.设置应该比mysql设置的超时时间短
|
||||
max-lifetime: 1800000
|
||||
# 用于测试连接是否可用的查询语句
|
||||
connection-test-query: SELECT 1
|
||||
# 监控配置
|
||||
application:
|
||||
name: "ChestnutCMS"
|
||||
boot:
|
||||
admin:
|
||||
client:
|
||||
# 增加客户端开关
|
||||
enabled: false
|
||||
# Admin Server URL
|
||||
url: http://127.0.0.1:8090/admin
|
||||
instance:
|
||||
service-host-type: IP
|
||||
username: chestnut
|
||||
password: 123456
|
||||
|
||||
# SaToken配置
|
||||
sa-token:
|
||||
# token名称 (同时也是cookie名称)
|
||||
token-name: Authorization
|
||||
# token前缀
|
||||
token-prefix: Bearer
|
||||
# token有效期,单位s 默认30天, -1代表永不过期
|
||||
timeout: 2592000
|
||||
# token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒
|
||||
active-timeout: -1
|
||||
# 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
|
||||
is-concurrent: true
|
||||
# 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
|
||||
is-share: true
|
||||
# token风格
|
||||
token-style: uuid
|
||||
# 是否输出操作日志
|
||||
is-log: true
|
||||
|
||||
# MyBatis配置
|
||||
mybatis-plus:
|
||||
global-config:
|
||||
enable-sql-runner: true
|
||||
# 搜索指定包别名
|
||||
typeAliasesPackage: com.chestnut.**.domain
|
||||
# 配置mapper的扫描,找到所有的mapper.xml映射文件
|
||||
mapperLocations: classpath*:mapper/**/*Mapper.xml
|
||||
configuration:
|
||||
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||||
|
||||
# 防止XSS攻击
|
||||
xss:
|
||||
# 过滤开关
|
||||
enabled: true
|
||||
mode: clean
|
||||
# 过滤链接
|
||||
urlPatterns:
|
||||
- /system/*
|
||||
- /monitor/*
|
||||
- /tool/*
|
||||
|
||||
xxl:
|
||||
job:
|
||||
enable: false
|
||||
accessToken: default_token
|
||||
adminAddresses: http://127.0.0.1:18080/xxl-job-admin
|
||||
executor:
|
||||
### 执行器AppName [选填]:执行器心跳注册分组依据;为空则关闭自动注册
|
||||
appname: chestnut-admin
|
||||
### 执行器注册 [选填]:优先使用该配置作为注册地址,为空时使用内嵌服务 ”IP:PORT“ 作为注册地址。从而更灵活的支持容器类型执行器动态IP和动态映射端口问题。
|
||||
#address:
|
||||
### 执行器IP [选填]:默认为空表示自动获取IP,多网卡时可手动设置指定IP,该IP不会绑定Host仅作为通讯实用;地址信息用于 "执行器注册" 和 "调度中心请求并触发任务";
|
||||
ip:
|
||||
### 执行器端口号 [选填]:小于等于0则自动获取;默认端口为9999,单机部署多个执行器时,注意要配置不同执行器端口;
|
||||
port: 9968
|
||||
### 执行器运行日志文件存储磁盘路径 [选填] :需要对该路径拥有读写权限;为空则使用默认路径;
|
||||
logpath: E:/dev/workspace_chestnut/ChestnutCMS/chestnut-modules/chestnut-xxljob/jobhandler
|
||||
### 执行器日志文件保存天数 [选填] : 过期日志自动清理, 限制值大于等于3时生效; 否则, 如-1, 关闭自动清理功能;默认:30
|
||||
# 项目相关配置
|
||||
chestnut:
|
||||
# 名称
|
||||
name: 栗子内容管理系统
|
||||
# 代号
|
||||
alias: ChestnutCMS
|
||||
# 版本
|
||||
version: 1.5.1
|
||||
# 版权年份
|
||||
copyrightYear: 2022-2024
|
||||
system:
|
||||
# 演示模式开关
|
||||
demoMode: true
|
||||
# 文件路径 示例( Windows配置D:/chestnut/uploadPath,Linux配置 /home/app/uploadPath)
|
||||
uploadPath: /home/app/uploadPath
|
||||
# 验证码类型 math 数组计算 char 字符验证
|
||||
captchaType: math
|
||||
freemarker:
|
||||
templateLoaderPath: /home/app/statics
|
||||
cms:
|
||||
resourceRoot: /home/app/wwwroot_release
|
||||
|
||||
# 开发环境配置
|
||||
server:
|
||||
# 服务器的HTTP端口,默认为8090
|
||||
port: 8090
|
||||
servlet:
|
||||
# 应用的访问路径
|
||||
context-path: /
|
||||
tomcat:
|
||||
# tomcat的URI编码
|
||||
uri-encoding: UTF-8
|
||||
# 连接数满后的排队数,默认为100
|
||||
accept-count: 1000
|
||||
threads:
|
||||
# tomcat最大线程数,默认为200
|
||||
max: 800
|
||||
# Tomcat启动初始化的线程数,默认值10
|
||||
min-spare: 100
|
||||
|
||||
# 日志配置
|
||||
logging:
|
||||
level:
|
||||
com.chestnut: debug
|
||||
org.springframework: warn
|
||||
|
||||
# Spring配置
|
||||
spring:
|
||||
# 资源信息
|
||||
messages:
|
||||
# 国际化资源文件路径
|
||||
basename: i18n/messages
|
||||
# 文件上传
|
||||
servlet:
|
||||
multipart:
|
||||
# 单个文件大小
|
||||
max-file-size: 20MB
|
||||
# 设置总上传的文件大小
|
||||
max-request-size: 100MB
|
||||
# 服务模块
|
||||
devtools:
|
||||
restart:
|
||||
# 热部署开关
|
||||
enabled: false
|
||||
freemarker:
|
||||
check-template-location: false
|
||||
elasticsearch:
|
||||
uris: http://cc-elasticsearch:9200
|
||||
username: elastic
|
||||
password: hello1234
|
||||
# redis 配置
|
||||
data:
|
||||
redis:
|
||||
# 地址
|
||||
host: cc-redis
|
||||
# 端口,默认为6379
|
||||
port: 6379
|
||||
# 数据库索引
|
||||
database: 0
|
||||
# 密码
|
||||
password: b18a03
|
||||
# 连接超时时间
|
||||
timeout: 10s
|
||||
lettuce:
|
||||
pool:
|
||||
# 连接池中的最小空闲连接
|
||||
min-idle: 0
|
||||
# 连接池中的最大空闲连接
|
||||
max-idle: 8
|
||||
# 连接池的最大数据库连接数
|
||||
max-active: 8
|
||||
# #连接池最大阻塞等待时间(使用负值表示没有限制)
|
||||
max-wait: -1ms
|
||||
flyway:
|
||||
enabled: false
|
||||
# 迁移sql脚本文件存放路径,默认:classpath:db/migration
|
||||
locations: classpath:db/migration/mysql
|
||||
# 迁移sql脚本文件名称的前缀,默认:V
|
||||
sql-migration-prefix: V
|
||||
# 迁移sql脚本文件名称分隔符,默认2个下划线:__
|
||||
sql-migration-separator: __
|
||||
# 迁移sql脚本文件名称后缀
|
||||
sql-migration-suffixes: .sql
|
||||
# 迁移时是否进行校验
|
||||
validate-on-migrate: true
|
||||
# 当迁移发现数据库非空且存在没有元数据的表时,自动执行基准迁移,新建schema_version表
|
||||
baseline-on-migrate: true
|
||||
# 数据库配置
|
||||
datasource:
|
||||
# type: com.alibaba.druid.pool.DruidDataSource
|
||||
type: com.zaxxer.hikari.HikariDataSource
|
||||
dynamic:
|
||||
primary: master
|
||||
# 严格模式 匹配不到数据源则报错
|
||||
strict: true
|
||||
# 主库
|
||||
datasource:
|
||||
master:
|
||||
type: ${spring.datasource.type}
|
||||
driverClassName: com.mysql.cj.jdbc.Driver
|
||||
url: jdbc:mysql://127.0.0.1:3308/chestnut_cms?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
|
||||
username: root
|
||||
password: hello1234
|
||||
# 从库
|
||||
#slave:
|
||||
# lazy: true
|
||||
# type: ${spring.datasource.type}
|
||||
# driverClassName: com.mysql.cj.jdbc.Driver
|
||||
# url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
|
||||
# username:
|
||||
# password:
|
||||
hikari:
|
||||
# 连接池名
|
||||
pool-name: HikariCP
|
||||
# 连接超时时间:毫秒, 默认30秒
|
||||
connection-timeout: 2000
|
||||
# 最小空闲连接,默认值10,小于0或大于maximum-pool-size,都会重置为maximum-pool-size
|
||||
minimum-idle: 5
|
||||
# 最大连接数,小于等于0会被重置为默认值10;大于零小于1会被重置为minimum-idle的值
|
||||
maximum-pool-size: 20
|
||||
# 空闲连接最大存活时间,默认值600000(10分钟),大于等于max-lifetime且max-lifetime>0,会被重置为0;不等于0且小于10秒,会被重置为10秒。
|
||||
idle-timeout: 200000
|
||||
# 连接池返回的连接默认自动提交,默认只 true
|
||||
auto-commit: true
|
||||
# 连接最大存活时间,不等于0且小于30秒,会被重置为默认值30分钟.设置应该比mysql设置的超时时间短
|
||||
max-lifetime: 1800000
|
||||
# 用于测试连接是否可用的查询语句
|
||||
connection-test-query: SELECT 1
|
||||
# 监控配置
|
||||
application:
|
||||
name: "ChestnutCMS"
|
||||
boot:
|
||||
admin:
|
||||
client:
|
||||
# 增加客户端开关
|
||||
enabled: false
|
||||
# Admin Server URL
|
||||
url: http://127.0.0.1:8090/admin
|
||||
instance:
|
||||
service-host-type: IP
|
||||
username: chestnut
|
||||
password: 123456
|
||||
|
||||
# SaToken配置
|
||||
sa-token:
|
||||
# token名称 (同时也是cookie名称)
|
||||
token-name: Authorization
|
||||
# token前缀
|
||||
token-prefix: Bearer
|
||||
# token有效期,单位s 默认30天, -1代表永不过期
|
||||
timeout: 2592000
|
||||
# token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒
|
||||
active-timeout: -1
|
||||
# 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
|
||||
is-concurrent: true
|
||||
# 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
|
||||
is-share: true
|
||||
# token风格
|
||||
token-style: uuid
|
||||
# 是否输出操作日志
|
||||
is-log: true
|
||||
|
||||
# MyBatis配置
|
||||
mybatis-plus:
|
||||
global-config:
|
||||
enable-sql-runner: true
|
||||
# 搜索指定包别名
|
||||
typeAliasesPackage: com.chestnut.**.domain
|
||||
# 配置mapper的扫描,找到所有的mapper.xml映射文件
|
||||
mapperLocations: classpath*:mapper/**/*Mapper.xml
|
||||
configuration:
|
||||
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||||
|
||||
# 防止XSS攻击
|
||||
xss:
|
||||
# 过滤开关
|
||||
enabled: true
|
||||
mode: clean
|
||||
# 过滤链接
|
||||
urlPatterns:
|
||||
- /system/*
|
||||
- /monitor/*
|
||||
- /tool/*
|
||||
|
||||
xxl:
|
||||
job:
|
||||
enable: false
|
||||
accessToken: default_token
|
||||
adminAddresses: http://127.0.0.1:18080/xxl-job-admin
|
||||
executor:
|
||||
### 执行器AppName [选填]:执行器心跳注册分组依据;为空则关闭自动注册
|
||||
appname: chestnut-admin
|
||||
### 执行器注册 [选填]:优先使用该配置作为注册地址,为空时使用内嵌服务 ”IP:PORT“ 作为注册地址。从而更灵活的支持容器类型执行器动态IP和动态映射端口问题。
|
||||
#address:
|
||||
### 执行器IP [选填]:默认为空表示自动获取IP,多网卡时可手动设置指定IP,该IP不会绑定Host仅作为通讯实用;地址信息用于 "执行器注册" 和 "调度中心请求并触发任务";
|
||||
ip:
|
||||
### 执行器端口号 [选填]:小于等于0则自动获取;默认端口为9999,单机部署多个执行器时,注意要配置不同执行器端口;
|
||||
port: 9968
|
||||
### 执行器运行日志文件存储磁盘路径 [选填] :需要对该路径拥有读写权限;为空则使用默认路径;
|
||||
logpath: E:/dev/workspace_chestnut/ChestnutCMS/chestnut-modules/chestnut-xxljob/jobhandler
|
||||
### 执行器日志文件保存天数 [选填] : 过期日志自动清理, 限制值大于等于3时生效; 否则, 如-1, 关闭自动清理功能;默认:30
|
||||
logretentiondays: 30
|
||||
@ -4,9 +4,6 @@ ALTER TABLE cms_image DROP COLUMN deleted;
|
||||
ALTER TABLE cms_audio DROP COLUMN deleted;
|
||||
ALTER TABLE cms_video DROP COLUMN deleted;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for b_cms_content
|
||||
-- ----------------------------
|
||||
CREATE TABLE `b_cms_content` (
|
||||
`content_id` bigint NOT NULL COMMENT '主键ID',
|
||||
`site_id` bigint NOT NULL COMMENT '所属站点ID',
|
||||
@ -69,9 +66,7 @@ CREATE TABLE `b_cms_content` (
|
||||
`backup_remark` varchar(100) COLLATE utf8mb4_general_ci DEFAULT NULL,
|
||||
PRIMARY KEY (`backup_id`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
|
||||
-- ----------------------------
|
||||
-- Table structure for b_cms_article_detail
|
||||
-- ----------------------------
|
||||
|
||||
CREATE TABLE `b_cms_article_detail` (
|
||||
`content_id` bigint NOT NULL COMMENT 'ID',
|
||||
`site_id` bigint NOT NULL,
|
||||
@ -85,9 +80,7 @@ CREATE TABLE `b_cms_article_detail` (
|
||||
`backup_remark` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
|
||||
PRIMARY KEY (`backup_id`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
|
||||
-- ----------------------------
|
||||
-- Table structure for b_cms_image
|
||||
-- ----------------------------
|
||||
|
||||
CREATE TABLE `b_cms_image` (
|
||||
`image_id` bigint NOT NULL COMMENT '主键ID',
|
||||
`site_id` bigint DEFAULT NULL,
|
||||
@ -114,9 +107,7 @@ CREATE TABLE `b_cms_image` (
|
||||
`backup_remark` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
|
||||
PRIMARY KEY (`backup_id`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
|
||||
-- ----------------------------
|
||||
-- Table structure for b_cms_audio
|
||||
-- ----------------------------
|
||||
|
||||
CREATE TABLE `b_cms_audio` (
|
||||
`audio_id` bigint NOT NULL COMMENT 'ID',
|
||||
`content_id` bigint NOT NULL COMMENT '所属内容ID',
|
||||
@ -145,9 +136,7 @@ CREATE TABLE `b_cms_audio` (
|
||||
`backup_remark` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
|
||||
PRIMARY KEY (`backup_id`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
|
||||
-- ----------------------------
|
||||
-- Table structure for b_cms_video
|
||||
-- ----------------------------
|
||||
|
||||
CREATE TABLE `b_cms_video` (
|
||||
`video_id` bigint NOT NULL,
|
||||
`content_id` bigint NOT NULL COMMENT '所属内容ID',
|
||||
@ -179,9 +168,6 @@ CREATE TABLE `b_cms_video` (
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
|
||||
|
||||
-- __CC_IGNORE__
|
||||
-- ----------------------------
|
||||
-- Table structure for cms_book
|
||||
-- ----------------------------
|
||||
CREATE TABLE `cms_book` (
|
||||
`content_id` bigint NOT NULL COMMENT 'ID',
|
||||
`site_id` bigint NOT NULL COMMENT '所属站点ID',
|
||||
@ -199,9 +185,7 @@ CREATE TABLE `cms_book` (
|
||||
`completed` varchar(1) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '是否完结',
|
||||
PRIMARY KEY (`content_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
-- ----------------------------
|
||||
-- Table structure for b_cms_book
|
||||
-- ----------------------------
|
||||
|
||||
CREATE TABLE `b_cms_book` (
|
||||
`content_id` bigint NOT NULL COMMENT 'ID',
|
||||
`site_id` bigint NOT NULL COMMENT '所属站点ID',
|
||||
@ -223,9 +207,7 @@ CREATE TABLE `b_cms_book` (
|
||||
`backup_remark` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
|
||||
PRIMARY KEY (`backup_id`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
-- ----------------------------
|
||||
-- Table structure for cms_book_chapter
|
||||
-- ----------------------------
|
||||
|
||||
CREATE TABLE `cms_book_chapter` (
|
||||
`chapter_id` bigint NOT NULL COMMENT 'ID',
|
||||
`site_id` bigint NOT NULL COMMENT '所属站点ID',
|
||||
@ -243,9 +225,7 @@ CREATE TABLE `cms_book_chapter` (
|
||||
`remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备注',
|
||||
PRIMARY KEY (`chapter_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
-- ----------------------------
|
||||
-- Table structure for b_cms_book_chapter
|
||||
-- ----------------------------
|
||||
|
||||
CREATE TABLE `b_cms_book_chapter` (
|
||||
`chapter_id` bigint NOT NULL COMMENT 'ID',
|
||||
`site_id` bigint NOT NULL COMMENT '所属站点ID',
|
||||
|
||||
@ -0,0 +1,83 @@
|
||||
UPDATE cms_content SET `link_flag` = 'N' WHERE link_flag is null;
|
||||
ALTER TABLE cms_content MODIFY COLUMN `link_flag` varchar(1) DEFAULT 'N';
|
||||
UPDATE cms_content SET `is_lock` = 'N' WHERE is_lock is null;
|
||||
ALTER TABLE cms_content MODIFY COLUMN `is_lock` varchar(1) DEFAULT 'N';
|
||||
|
||||
ALTER TABLE cms_video MODIFY COLUMN `path` varchar(1000);
|
||||
ALTER TABLE b_cms_video MODIFY COLUMN `path` varchar(1000);
|
||||
|
||||
ALTER TABLE cms_content ADD COLUMN `images` varchar(500);
|
||||
UPDATE cms_content SET images = CASE WHEN logo IS NOT NULL AND logo != '' THEN CONCAT('["', logo, '"]') ELSE '[]' END;
|
||||
ALTER TABLE cms_content DROP COLUMN logo;
|
||||
|
||||
ALTER TABLE cms_article_detail DROP COLUMN content_json;
|
||||
ALTER TABLE cms_article_detail ADD COLUMN `format` varchar(10);
|
||||
UPDATE cms_article_detail SET format = 'RichText';
|
||||
|
||||
CREATE TABLE `cms_content_op_log` (
|
||||
`log_id` bigint NOT NULL COMMENT 'ID',
|
||||
`site_id` bigint NOT NULL COMMENT '站点ID',
|
||||
`content_id` bigint NOT NULL COMMENT '内容ID',
|
||||
`type` varchar(20) COLLATE utf8mb4_general_ci NOT NULL COMMENT '操作方式',
|
||||
`details` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '操作明细',
|
||||
`operator_type` varchar(20) COLLATE utf8mb4_general_ci NOT NULL COMMENT '操作人类型',
|
||||
`operator` varchar(50) COLLATE utf8mb4_general_ci NOT NULL COMMENT '操作人',
|
||||
`log_time` datetime NOT NULL COMMENT '日志时间',
|
||||
PRIMARY KEY (`log_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
||||
|
||||
/* __CC_IGNORE__ */
|
||||
CREATE TABLE `cc_check_latest_version_log` (
|
||||
`log_id` bigint NOT NULL COMMENT 'ID',
|
||||
`from` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '来源',
|
||||
`referer` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT 'Referer',
|
||||
`create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime NOT NULL COMMENT '创建时间',
|
||||
`update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备注',
|
||||
PRIMARY KEY (`log_id`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
|
||||
|
||||
CREATE TABLE `cc_certificate` (
|
||||
`cert_id` bigint NOT NULL COMMENT 'ID',
|
||||
`issuer` varchar(50) COLLATE utf8mb4_general_ci NOT NULL COMMENT '签发者类型',
|
||||
`domain` varchar(100) COLLATE utf8mb4_general_ci NOT NULL COMMENT '域名',
|
||||
`acme_account_id` bigint DEFAULT NULL COMMENT '关联ACME账号ID',
|
||||
`issue_time` bigint DEFAULT NULL COMMENT '证书签发时间',
|
||||
`expire_time` bigint DEFAULT NULL COMMENT '证书过期时间',
|
||||
`key_path` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '证书Key路径',
|
||||
`crt_path` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '证书路径',
|
||||
`crt_country` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '证书信息:国家',
|
||||
`crt_state` varchar(100) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '证书信息:省',
|
||||
`crt_locality` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '证书信息:地区',
|
||||
`crt_organization` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '证书信息:组织机构',
|
||||
`status` varchar(20) COLLATE utf8mb4_general_ci NOT NULL COMMENT '状态',
|
||||
`config_props` varchar(500) CHARACTER SET utf8mb4 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 (`cert_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='域名证书表';
|
||||
|
||||
CREATE TABLE `cc_acme_account` (
|
||||
`account_id` bigint NOT NULL,
|
||||
`issuer` varchar(50) COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`key_pair_path` varchar(255) COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`location_url` varchar(500) COLLATE utf8mb4_general_ci DEFAULT NULL,
|
||||
`domain_num` int NOT NULL,
|
||||
`contact` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,
|
||||
`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 (`account_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='ACME账号表';
|
||||
INSERT INTO `sys_menu` VALUES (2082, '域名证书', 3, 5, 'deploy/certificate', 'deploy/certificate/index', '', 'N', 'Y', 'C', 'Y', '0', 'deploy:cert:view', 'skill', 'admin', '2025-01-14 00:00:00', '', NULL, '');
|
||||
INSERT INTO `sys_i18n_dict` VALUES (632978182307909, 'zh-CN', 'MENU.NAME.2082', '证书管理');
|
||||
INSERT INTO `sys_i18n_dict` VALUES (633640198516805, 'en', 'MENU.NAME.2082', 'Domain Cert');
|
||||
INSERT INTO `sys_i18n_dict` VALUES (633640198524997, 'zh-TW', 'MENU.NAME.2082', '證書管理');
|
||||
/* __CC_IGNORE_END__ */
|
||||
@ -1,28 +0,0 @@
|
||||
package com.chestnut.member;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
import com.chestnut.member.domain.Member;
|
||||
import com.chestnut.member.service.IMemberExpConfigService;
|
||||
import com.chestnut.member.service.IMemberService;
|
||||
|
||||
@SpringBootTest
|
||||
public class MemberTest {
|
||||
|
||||
@Autowired
|
||||
private IMemberService memberService;
|
||||
|
||||
@Autowired
|
||||
private IMemberExpConfigService expConfigService;
|
||||
|
||||
@Test
|
||||
void testMemberSignIn() {
|
||||
Member member = this.memberService.getById(398339741712453L);
|
||||
|
||||
expConfigService.list().forEach(expConfig -> {
|
||||
|
||||
expConfigService.triggerExpOperation(expConfig.getOpType(), member.getMemberId());
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<artifactId>chestnut-cms</artifactId>
|
||||
<version>1.5.0</version>
|
||||
<version>1.5.1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>chestnut-cms-advertisement</artifactId>
|
||||
|
||||
@ -29,7 +29,6 @@ import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* 广告页面部件内容核心数据处理器
|
||||
@ -61,6 +60,7 @@ public class AdCoreDataHandler implements ICoreDataHandler {
|
||||
files.forEach(f -> {
|
||||
List<CmsAdvertisement> list = JacksonUtils.fromList(f, CmsAdvertisement.class);
|
||||
for (CmsAdvertisement data : list) {
|
||||
Long oldAdvertisementId = data.getAdvertisementId();
|
||||
try {
|
||||
data.setAdvertisementId(IdUtils.getSnowflakeId());
|
||||
data.setSiteId(context.getSite().getSiteId());
|
||||
@ -70,8 +70,7 @@ public class AdCoreDataHandler implements ICoreDataHandler {
|
||||
data.setRedirectUrl(context.dealInternalUrl(data.getRedirectUrl()));
|
||||
advertisementService.save(data);
|
||||
} catch (Exception e) {
|
||||
AsyncTaskManager.addErrMessage("导入广告数据失败:" + data.getName()
|
||||
+ "[" + data.getAdvertisementId() + "]");
|
||||
AsyncTaskManager.addErrMessage("导入广告数据`" + oldAdvertisementId + "`失败:" + e.getMessage());
|
||||
log.error("Import advertisement failed: {}", data.getAdvertisementId(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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.advertisement.cache;
|
||||
|
||||
import com.chestnut.common.redis.IMonitoredCache;
|
||||
import com.chestnut.common.redis.RedisCache;
|
||||
import com.chestnut.contentcore.config.CMSConfig;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* AdMonitoredCache
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
*/
|
||||
@Component(IMonitoredCache.BEAN_PREFIX + AdMonitoredCache.ID)
|
||||
@RequiredArgsConstructor
|
||||
public class AdMonitoredCache implements IMonitoredCache<Map<String, String>> {
|
||||
|
||||
public static final String ID = "AD";
|
||||
|
||||
private static final String CACHE_PREFIX = CMSConfig.CachePrefix + "adv-ids";
|
||||
|
||||
private final RedisCache redisCache;
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCacheName() {
|
||||
return "{MONITORED.CACHE.AD}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCacheKey() {
|
||||
return CACHE_PREFIX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getCache(String cacheKey) {
|
||||
return redisCache.getCacheMap(cacheKey, String.class);
|
||||
}
|
||||
|
||||
public Map<String, String> getCache(Supplier<Map<String, String>> supplier) {
|
||||
return redisCache.getCacheMap(CACHE_PREFIX, String.class, supplier);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
this.redisCache.deleteObject(CACHE_PREFIX);
|
||||
}
|
||||
}
|
||||
@ -15,16 +15,16 @@
|
||||
*/
|
||||
package com.chestnut.advertisement.pojo.vo;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
||||
import com.chestnut.advertisement.domain.CmsAdvertisement;
|
||||
import com.chestnut.common.annotation.XComment;
|
||||
import com.chestnut.contentcore.util.InternalUrlUtils;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 广告数据VO
|
||||
*
|
||||
@ -36,79 +36,49 @@ import lombok.Setter;
|
||||
@NoArgsConstructor
|
||||
public class AdvertisementVO {
|
||||
|
||||
/**
|
||||
* 广告ID
|
||||
*/
|
||||
@XComment("广告ID")
|
||||
private Long advertisementId;
|
||||
|
||||
/**
|
||||
* 所属广告位ID
|
||||
*/
|
||||
@XComment("所属广告版本(页面部件)ID")
|
||||
private Long adSpaceId;
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
@XComment("类型")
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 名称
|
||||
*/
|
||||
@XComment("名称")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 权重
|
||||
*/
|
||||
@XComment("权重")
|
||||
private Integer weight;
|
||||
|
||||
/**
|
||||
* 关键词
|
||||
*/
|
||||
@XComment("关键词")
|
||||
private String keywords;
|
||||
|
||||
/**
|
||||
* 状态
|
||||
*/
|
||||
@XComment("状态")
|
||||
private String state;
|
||||
|
||||
/**
|
||||
* 上线时间
|
||||
*/
|
||||
@XComment("上线时间")
|
||||
private LocalDateTime onlineDate;
|
||||
|
||||
/**
|
||||
* 下线时间
|
||||
*/
|
||||
@XComment("下线时间")
|
||||
private LocalDateTime offlineDate;
|
||||
|
||||
/**
|
||||
* 跳转链接
|
||||
*/
|
||||
@XComment("原始跳转链接")
|
||||
private String redirectUrl;
|
||||
|
||||
/**
|
||||
* 跳转链接(可设置为中转地址)
|
||||
*/
|
||||
@XComment("实际跳转链接(可设置为中转地址)")
|
||||
private String link;
|
||||
|
||||
/**
|
||||
* 素材链接
|
||||
*/
|
||||
@XComment("素材路径")
|
||||
private String resourcePath;
|
||||
|
||||
/**
|
||||
* 素材真实地址
|
||||
*/
|
||||
@XComment("素材访问链接")
|
||||
private String resourceSrc;
|
||||
|
||||
/**
|
||||
* 创建人
|
||||
*/
|
||||
@XComment("创建人")
|
||||
private String createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@XComment("创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
public AdvertisementVO(CmsAdvertisement ad) {
|
||||
|
||||
@ -15,35 +15,41 @@
|
||||
*/
|
||||
package com.chestnut.advertisement.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.chestnut.advertisement.AdSpacePageWidgetType;
|
||||
import com.chestnut.advertisement.IAdvertisementType;
|
||||
import com.chestnut.advertisement.cache.AdMonitoredCache;
|
||||
import com.chestnut.advertisement.domain.CmsAdvertisement;
|
||||
import com.chestnut.advertisement.mapper.CmsAdvertisementMapper;
|
||||
import com.chestnut.advertisement.pojo.dto.AdvertisementDTO;
|
||||
import com.chestnut.advertisement.service.IAdvertisementService;
|
||||
import com.chestnut.common.async.AsyncTaskManager;
|
||||
import com.chestnut.common.exception.CommonErrorCode;
|
||||
import com.chestnut.common.utils.Assert;
|
||||
import com.chestnut.common.utils.IdUtils;
|
||||
import com.chestnut.contentcore.core.IPageWidget;
|
||||
import com.chestnut.contentcore.core.IPageWidgetType;
|
||||
import com.chestnut.contentcore.domain.CmsPageWidget;
|
||||
import com.chestnut.contentcore.domain.CmsSite;
|
||||
import com.chestnut.contentcore.properties.SiteApiUrlProperty;
|
||||
import com.chestnut.contentcore.publish.IStaticizeType;
|
||||
import com.chestnut.contentcore.service.IPageWidgetService;
|
||||
import com.chestnut.contentcore.service.ISiteService;
|
||||
import com.chestnut.system.fixed.dict.EnableOrDisable;
|
||||
import com.chestnut.system.security.StpAdminUtil;
|
||||
import freemarker.template.TemplateException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.chestnut.contentcore.domain.CmsSite;
|
||||
import com.chestnut.contentcore.properties.SiteApiUrlProperty;
|
||||
import com.chestnut.contentcore.service.ISiteService;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.chestnut.advertisement.IAdvertisementType;
|
||||
import com.chestnut.advertisement.domain.CmsAdvertisement;
|
||||
import com.chestnut.advertisement.mapper.CmsAdvertisementMapper;
|
||||
import com.chestnut.advertisement.pojo.dto.AdvertisementDTO;
|
||||
import com.chestnut.advertisement.service.IAdvertisementService;
|
||||
import com.chestnut.common.exception.CommonErrorCode;
|
||||
import com.chestnut.common.redis.RedisCache;
|
||||
import com.chestnut.common.utils.Assert;
|
||||
import com.chestnut.common.utils.IdUtils;
|
||||
import com.chestnut.contentcore.config.CMSConfig;
|
||||
import com.chestnut.contentcore.domain.CmsPageWidget;
|
||||
import com.chestnut.contentcore.service.IPageWidgetService;
|
||||
import com.chestnut.system.fixed.dict.EnableOrDisable;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 广告数据服务实现类
|
||||
@ -57,9 +63,7 @@ import lombok.RequiredArgsConstructor;
|
||||
public class AdvertisementServiceImpl extends ServiceImpl<CmsAdvertisementMapper, CmsAdvertisement>
|
||||
implements IAdvertisementService {
|
||||
|
||||
private static final String CACHE_KEY_ADV_IDS = CMSConfig.CachePrefix + "adv-ids";
|
||||
|
||||
private final RedisCache redisCache;
|
||||
private final AdMonitoredCache adCache;
|
||||
|
||||
private final Map<String, IAdvertisementType> advertisementTypes;
|
||||
|
||||
@ -67,6 +71,8 @@ public class AdvertisementServiceImpl extends ServiceImpl<CmsAdvertisementMapper
|
||||
|
||||
private final ISiteService siteService;
|
||||
|
||||
private final AsyncTaskManager asyncTaskManager;
|
||||
|
||||
@Override
|
||||
public IAdvertisementType getAdvertisementType(String typeId) {
|
||||
return this.advertisementTypes.get(IAdvertisementType.BEAN_NAME_PREFIX + typeId);
|
||||
@ -79,10 +85,12 @@ public class AdvertisementServiceImpl extends ServiceImpl<CmsAdvertisementMapper
|
||||
|
||||
@Override
|
||||
public Map<String, String> getAdvertisementMap() {
|
||||
return this.redisCache.getCacheMap(CACHE_KEY_ADV_IDS,
|
||||
() -> this.lambdaQuery().select(List.of(CmsAdvertisement::getAdvertisementId, CmsAdvertisement::getName)).list()
|
||||
.stream().collect(
|
||||
Collectors.toMap(ad -> ad.getAdvertisementId().toString(), CmsAdvertisement::getName)));
|
||||
return adCache.getCache(() -> {
|
||||
return this.lambdaQuery()
|
||||
.select(List.of(CmsAdvertisement::getAdvertisementId, CmsAdvertisement::getName))
|
||||
.list().stream()
|
||||
.collect(Collectors.toMap(ad -> ad.getAdvertisementId().toString(), CmsAdvertisement::getName));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -99,7 +107,7 @@ public class AdvertisementServiceImpl extends ServiceImpl<CmsAdvertisementMapper
|
||||
advertisement.createBy(dto.getOperator().getUsername());
|
||||
this.save(advertisement);
|
||||
|
||||
this.redisCache.deleteObject(CACHE_KEY_ADV_IDS);
|
||||
this.adCache.clear();
|
||||
return advertisement;
|
||||
}
|
||||
|
||||
@ -116,12 +124,14 @@ public class AdvertisementServiceImpl extends ServiceImpl<CmsAdvertisementMapper
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void deleteAdvertisement(List<Long> advertisementIds) {
|
||||
this.removeByIds(advertisementIds);
|
||||
this.redisCache.deleteObject(CACHE_KEY_ADV_IDS);
|
||||
this.adCache.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void enableAdvertisement(List<Long> advertisementIds, String operator) {
|
||||
List<CmsAdvertisement> list = this.listByIds(advertisementIds);
|
||||
for (CmsAdvertisement ad : list) {
|
||||
@ -134,6 +144,7 @@ public class AdvertisementServiceImpl extends ServiceImpl<CmsAdvertisementMapper
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void disableAdvertisement(List<Long> advertisementIds, String operator) {
|
||||
List<CmsAdvertisement> list = this.listByIds(advertisementIds);
|
||||
for (CmsAdvertisement ad : list) {
|
||||
@ -143,7 +154,14 @@ public class AdvertisementServiceImpl extends ServiceImpl<CmsAdvertisementMapper
|
||||
}
|
||||
}
|
||||
this.updateBatchById(list);
|
||||
// todo 重新发布
|
||||
// 重新发布
|
||||
asyncTaskManager.execute(() -> {
|
||||
CmsPageWidget pageWidget = this.pageWidgetService.getById(list.get(0).getAdSpaceId());
|
||||
IPageWidgetType pwt = pageWidgetService.getPageWidgetType(AdSpacePageWidgetType.ID);
|
||||
IPageWidget pw = pwt.loadPageWidget(pageWidget);
|
||||
pw.setOperator(StpAdminUtil.getLoginUser());
|
||||
pw.publish();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -45,11 +45,15 @@ import java.util.Map;
|
||||
public class CmsAdvertisementTag extends AbstractListTag {
|
||||
|
||||
public final static String TAG_NAME = "cms_advertisement";
|
||||
public final static String NAME = "{FREEMARKER.TAG.NAME." + TAG_NAME + "}";
|
||||
public final static String DESC = "{FREEMARKER.TAG.DESC." + TAG_NAME + "}";
|
||||
public final static String NAME = "{FREEMARKER.TAG." + TAG_NAME + ".NAME}";
|
||||
public final static String DESC = "{FREEMARKER.TAG." + TAG_NAME + ".DESC}";
|
||||
public final static String ATTR_USAGE_CODE = "{FREEMARKER.TAG." + TAG_NAME + ".code}";
|
||||
public final static String ATTR_USAGE_TYPE = "{FREEMARKER.TAG." + TAG_NAME + ".type}";
|
||||
public final static String ATTR_OPTION_TYPE_NONE = "{FREEMARKER.TAG." + TAG_NAME + ".type.None}";
|
||||
public final static String ATTR_OPTION_TYPE_STAT = "{FREEMARKER.TAG." + TAG_NAME + ".type.Stat}";
|
||||
|
||||
final static String TagAttr_Code = "code";
|
||||
final static String TagAttr_RedirectType = "type";
|
||||
final static String ATTR_CODE = "code";
|
||||
final static String ATTR_TYPE = "type";
|
||||
|
||||
private final IAdvertisementService advertisementService;
|
||||
|
||||
@ -58,23 +62,23 @@ public class CmsAdvertisementTag extends AbstractListTag {
|
||||
@Override
|
||||
public List<TagAttr> getTagAttrs() {
|
||||
List<TagAttr> tagAttrs = super.getTagAttrs();
|
||||
tagAttrs.add(new TagAttr(TagAttr_Code, true, TagAttrDataType.STRING, "广告位编码"));
|
||||
tagAttrs.add(new TagAttr(TagAttr_RedirectType, false, TagAttrDataType.STRING, "广告跳转方式",
|
||||
tagAttrs.add(new TagAttr(ATTR_CODE, true, TagAttrDataType.STRING, ATTR_USAGE_CODE));
|
||||
tagAttrs.add(new TagAttr(ATTR_TYPE, false, TagAttrDataType.STRING, ATTR_USAGE_TYPE,
|
||||
RedirectType.toTagAttrOptions(), RedirectType.None.name()));
|
||||
return tagAttrs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TagPageData prepareData(Environment env, Map<String, String> attrs, boolean page, int size, int pageIndex) throws TemplateException {
|
||||
String code = MapUtils.getString(attrs, TagAttr_Code);
|
||||
String redirectType = MapUtils.getString(attrs, TagAttr_RedirectType, RedirectType.None.name());
|
||||
String code = MapUtils.getString(attrs, ATTR_CODE);
|
||||
String redirectType = MapUtils.getString(attrs, ATTR_TYPE, RedirectType.None.name());
|
||||
|
||||
Long siteId = TemplateUtils.evalSiteId(env);
|
||||
CmsPageWidget adSpace = this.pageWidgetService.getOne(new LambdaQueryWrapper<CmsPageWidget>()
|
||||
.eq(CmsPageWidget::getSiteId, siteId)
|
||||
.eq(CmsPageWidget::getCode, code));
|
||||
if (adSpace == null) {
|
||||
throw new TemplateException(StringUtils.messageFormat("<@{0}>AD place `{1}` not exists.", this.getTagName(), code), env) ;
|
||||
throw new TemplateException(StringUtils.messageFormat("Advertising space `{0}` not exists.", code), env) ;
|
||||
}
|
||||
String condition = MapUtils.getString(attrs, TagAttr.AttrName_Condition);
|
||||
|
||||
@ -83,9 +87,6 @@ public class CmsAdvertisementTag extends AbstractListTag {
|
||||
.eq(CmsAdvertisement::getState, EnableOrDisable.ENABLE);
|
||||
q.apply(StringUtils.isNotEmpty(condition), condition);
|
||||
Page<CmsAdvertisement> pageResult = this.advertisementService.page(new Page<>(pageIndex, size, page), q);
|
||||
if (pageIndex > 1 & pageResult.getRecords().isEmpty()) {
|
||||
throw new TemplateException(StringUtils.messageFormat("Page data empty: pageIndex = {0}", pageIndex), env) ;
|
||||
}
|
||||
TemplateContext context = FreeMarkerUtils.getTemplateContext(env);
|
||||
List<AdvertisementVO> list = pageResult.getRecords().stream().map(ad ->{
|
||||
AdvertisementVO vo = new AdvertisementVO(ad);
|
||||
@ -99,6 +100,11 @@ public class CmsAdvertisementTag extends AbstractListTag {
|
||||
return TagPageData.of(list, pageResult.getTotal());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<AdvertisementVO> getDataClass() {
|
||||
return AdvertisementVO.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTagName() {
|
||||
return TAG_NAME;
|
||||
@ -115,8 +121,8 @@ public class CmsAdvertisementTag extends AbstractListTag {
|
||||
}
|
||||
|
||||
private enum RedirectType {
|
||||
None("原始链接"),
|
||||
Stat("统计链接");
|
||||
None(ATTR_OPTION_TYPE_NONE),
|
||||
Stat(ATTR_OPTION_TYPE_STAT);
|
||||
|
||||
private final String desc;
|
||||
|
||||
|
||||
@ -5,8 +5,12 @@ CMS.CONTENCORE.PAGEWIDGET.ads=广告位
|
||||
ADVERTISEMENT.TYPE.image=图片
|
||||
|
||||
# 模板freemarker
|
||||
FREEMARKER.TAG.NAME.cms_advertisement=广告列表标签
|
||||
FREEMARKER.TAG.DESC.cms_advertisement=获取广告数据列表,内嵌<#list DataList as ad>${ad.name}</#list>遍历数据
|
||||
FREEMARKER.TAG.cms_advertisement.NAME=广告列表标签
|
||||
FREEMARKER.TAG.cms_advertisement.DESC=获取广告数据列表,内嵌`<#list DataList as ad>${ad.name}</#list>`遍历数据
|
||||
FREEMARKER.TAG.cms_advertisement.code=广告位编码
|
||||
FREEMARKER.TAG.cms_advertisement.type=广告链接类型
|
||||
FREEMARKER.TAG.cms_advertisement.type.None=原始链接
|
||||
FREEMARKER.TAG.cms_advertisement.type.Stat=统计链接
|
||||
|
||||
# 统计菜单
|
||||
STAT.MENU.CmsAdv=广告数据统计
|
||||
@ -16,4 +20,6 @@ STAT.MENU.CmsAdViewLog=广告展现日志
|
||||
|
||||
# 定时任务
|
||||
SCHEDULED_TASK.AdvertisementStatJob=广告统计任务
|
||||
SCHEDULED_TASK.AdvertisementPublishJob=广告定时发布下线任务
|
||||
SCHEDULED_TASK.AdvertisementPublishJob=广告定时发布下线任务
|
||||
|
||||
MONITORED.CACHE.AD=广告
|
||||
@ -5,8 +5,12 @@ CMS.CONTENCORE.PAGEWIDGET.ads=AD
|
||||
ADVERTISEMENT.TYPE.image=Image
|
||||
|
||||
# 模板freemarker
|
||||
FREEMARKER.TAG.NAME.cms_advertisement=Advertisement list tag
|
||||
FREEMARKER.TAG.DESC.cms_advertisement=Fetch advertising data list, use <#list> in tag like "<#list DataList as ad>${ad.name}</#list>" to walk through the list of ad.
|
||||
FREEMARKER.TAG.cms_advertisement.NAME=Advertisement list tag
|
||||
FREEMARKER.TAG.cms_advertisement.DESC=Fetch advertising data list, use `<#list>` in tag like `<#list DataList as ad>${ad.name}</#list>` to walk through the list of ad.
|
||||
FREEMARKER.TAG.cms_advertisement.code=Advertisement code
|
||||
FREEMARKER.TAG.cms_advertisement.type=Redirect type
|
||||
FREEMARKER.TAG.cms_advertisement.type.None=Source link
|
||||
FREEMARKER.TAG.cms_advertisement.type.Stat=Statistics link
|
||||
|
||||
# 统计菜单
|
||||
STAT.MENU.CmsAdv=Advertising Statistics
|
||||
@ -16,4 +20,6 @@ STAT.MENU.CmsAdViewLog=View Logs
|
||||
|
||||
# 定时任务
|
||||
SCHEDULED_TASK.AdvertisementStatJob=AD Statistics Task
|
||||
SCHEDULED_TASK.AdvertisementPublishJob=AD Publish/Offline Task
|
||||
SCHEDULED_TASK.AdvertisementPublishJob=AD Publish/Offline Task
|
||||
|
||||
MONITORED.CACHE.AD=Advertisement
|
||||
@ -5,8 +5,12 @@ CMS.CONTENCORE.PAGEWIDGET.ads=廣告位
|
||||
ADVERTISEMENT.TYPE.image=圖片
|
||||
|
||||
# 模板freemarker
|
||||
FREEMARKER.TAG.NAME.cms_advertisement=廣告列表標籤
|
||||
FREEMARKER.TAG.DESC.cms_advertisement=獲取廣告數據列表,內嵌<#list DataList as ad>${ad.name}</#list>遍曆數據
|
||||
FREEMARKER.TAG.cms_advertisement.NAME=廣告列表標籤
|
||||
FREEMARKER.TAG.cms_advertisement.DESC=獲取廣告數據列表,內嵌`<#list DataList as ad>${ad.name}</#list>`遍曆數據
|
||||
FREEMARKER.TAG.cms_advertisement.code=廣告位編碼
|
||||
FREEMARKER.TAG.cms_advertisement.type=廣告鏈接類型
|
||||
FREEMARKER.TAG.cms_advertisement.type.None=原始鏈接
|
||||
FREEMARKER.TAG.cms_advertisement.type.Stat=統計鏈接
|
||||
|
||||
# 統計菜單
|
||||
STAT.MENU.CmsAdv=廣告數據統計
|
||||
@ -17,3 +21,5 @@ STAT.MENU.CmsAdViewLog=廣告展現日誌
|
||||
# 定時任務
|
||||
SCHEDULED_TASK.AdvertisementStatJob=廣告統計任務
|
||||
SCHEDULED_TASK.AdvertisementPublishJob=廣告定時發布下線任務
|
||||
|
||||
MONITORED.CACHE.AD=廣告
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<artifactId>chestnut-cms</artifactId>
|
||||
<version>1.5.0</version>
|
||||
<version>1.5.1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>chestnut-cms-article</artifactId>
|
||||
|
||||
@ -23,7 +23,6 @@ import com.chestnut.common.utils.HtmlUtils;
|
||||
import com.chestnut.common.utils.SpringUtils;
|
||||
import com.chestnut.common.utils.StringUtils;
|
||||
import com.chestnut.contentcore.core.AbstractContent;
|
||||
import com.chestnut.contentcore.domain.CmsCatalog;
|
||||
import com.chestnut.contentcore.domain.CmsContent;
|
||||
import com.chestnut.contentcore.enums.ContentCopyType;
|
||||
import com.chestnut.contentcore.service.IResourceService;
|
||||
@ -31,6 +30,7 @@ import com.chestnut.contentcore.util.ResourceUtils;
|
||||
import com.chestnut.system.fixed.dict.YesOrNo;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
@ -41,11 +41,9 @@ public class ArticleContent extends AbstractContent<CmsArticleDetail> {
|
||||
private IResourceService resourceService;
|
||||
|
||||
@Override
|
||||
public Long add() {
|
||||
super.add();
|
||||
protected void add0() {
|
||||
if (!this.hasExtendEntity()) {
|
||||
this.getContentService().dao().save(this.getContentEntity());
|
||||
return this.getContentEntity().getContentId();
|
||||
return;
|
||||
}
|
||||
CmsArticleDetail articleDetail = this.getExtendEntity();
|
||||
articleDetail.setContentId(this.getContentEntity().getContentId());
|
||||
@ -60,23 +58,22 @@ public class ArticleContent extends AbstractContent<CmsArticleDetail> {
|
||||
}
|
||||
articleDetail.setContentHtml(contentHtml);
|
||||
// 正文首图作为logo
|
||||
if (StringUtils.isEmpty(this.getContentEntity().getLogo())
|
||||
if (StringUtils.isEmpty(this.getContentEntity().getImages())
|
||||
&& AutoArticleLogo.getValue(this.getSite().getConfigProps())) {
|
||||
this.getContentEntity().setLogo(this.getFirstImage(articleDetail.getContentHtml()));
|
||||
String firstImage = this.getFirstImage(articleDetail.getContentHtml());
|
||||
if (Objects.nonNull(firstImage)) {
|
||||
this.getContentEntity().setImages(List.of(firstImage));
|
||||
}
|
||||
}
|
||||
this.getContentService().dao().save(this.getContentEntity());
|
||||
this.getArticleService().dao().save(articleDetail);
|
||||
return this.getContentEntity().getContentId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long save() {
|
||||
super.save();
|
||||
protected void save0() {
|
||||
// 非映射内容或标题内容修改文章详情
|
||||
if (!this.hasExtendEntity()) {
|
||||
this.getContentService().dao().updateById(this.getContentEntity());
|
||||
this.getArticleService().dao().removeById(this.getContentEntity().getContentId());
|
||||
return this.getContentEntity().getContentId();
|
||||
return;
|
||||
}
|
||||
CmsArticleDetail articleDetail = this.getExtendEntity();
|
||||
// 处理内部链接
|
||||
@ -89,13 +86,14 @@ public class ArticleContent extends AbstractContent<CmsArticleDetail> {
|
||||
}
|
||||
articleDetail.setContentHtml(contentHtml);
|
||||
// 正文首图作为logo
|
||||
if (StringUtils.isEmpty(this.getContentEntity().getLogo())
|
||||
if (StringUtils.isEmpty(this.getContentEntity().getImages())
|
||||
&& AutoArticleLogo.getValue(this.getSite().getConfigProps())) {
|
||||
this.getContentEntity().setLogo(this.getFirstImage(articleDetail.getContentHtml()));
|
||||
String firstImage = this.getFirstImage(articleDetail.getContentHtml());
|
||||
if (Objects.nonNull(firstImage)) {
|
||||
this.getContentEntity().setImages(List.of(firstImage));
|
||||
}
|
||||
}
|
||||
this.getContentService().dao().updateById(this.getContentEntity());
|
||||
this.getArticleService().dao().saveOrUpdate(articleDetail);
|
||||
return this.getContentEntity().getContentId();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -116,8 +114,7 @@ public class ArticleContent extends AbstractContent<CmsArticleDetail> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() {
|
||||
super.delete();
|
||||
protected void delete0() {
|
||||
if (this.hasExtendEntity()) {
|
||||
this.getArticleService().dao()
|
||||
.deleteByIdAndBackup(this.getExtendEntity(), this.getOperatorUName());
|
||||
@ -125,16 +122,13 @@ public class ArticleContent extends AbstractContent<CmsArticleDetail> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public CmsContent copyTo(CmsCatalog toCatalog, Integer copyType) {
|
||||
CmsContent copyContent = super.copyTo(toCatalog, copyType);
|
||||
public void copyTo0(CmsContent newContent, Integer copyType) {
|
||||
if (this.hasExtendEntity() && ContentCopyType.isIndependency(copyType)) {
|
||||
Long newContentId = (Long) this.getParams().get("NewContentId");
|
||||
CmsArticleDetail newArticleDetail = new CmsArticleDetail();
|
||||
BeanUtils.copyProperties(this.getExtendEntity(), newArticleDetail, "contentId");
|
||||
newArticleDetail.setContentId(newContentId);
|
||||
newArticleDetail.setContentId(newContent.getContentId());
|
||||
this.getArticleService().dao().save(newArticleDetail);
|
||||
}
|
||||
return copyContent;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -35,23 +35,19 @@ import com.chestnut.contentcore.domain.*;
|
||||
import com.chestnut.contentcore.domain.dto.PublishPipeProp;
|
||||
import com.chestnut.contentcore.domain.vo.ContentVO;
|
||||
import com.chestnut.contentcore.enums.ContentCopyType;
|
||||
import com.chestnut.contentcore.enums.ContentOpType;
|
||||
import com.chestnut.contentcore.fixed.dict.ContentAttribute;
|
||||
import com.chestnut.contentcore.fixed.dict.ContentOpType;
|
||||
import com.chestnut.contentcore.service.ICatalogService;
|
||||
import com.chestnut.contentcore.service.IContentService;
|
||||
import com.chestnut.contentcore.service.IPublishPipeService;
|
||||
import com.chestnut.contentcore.service.ISiteService;
|
||||
import com.chestnut.contentcore.util.InternalUrlUtils;
|
||||
import com.chestnut.system.fixed.dict.YesOrNo;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
@Component(IContentType.BEAN_NAME_PREFIX + ArticleContentType.ID)
|
||||
@RequiredArgsConstructor
|
||||
@ -101,29 +97,22 @@ public class ArticleContentType implements IContentType {
|
||||
}
|
||||
|
||||
@Override
|
||||
public IContent<?> readRequest(HttpServletRequest request) throws IOException {
|
||||
ArticleDTO dto = JacksonUtils.from(request.getInputStream(), ArticleDTO.class);
|
||||
|
||||
CmsContent contentEntity;
|
||||
if (dto.getOpType() == ContentOpType.UPDATE) {
|
||||
contentEntity = this.contentService.dao().getById(dto.getContentId());
|
||||
Assert.notNull(contentEntity,
|
||||
() -> CommonErrorCode.DATA_NOT_FOUND_BY_ID.exception("contentId", dto.getContentId()));
|
||||
} else {
|
||||
contentEntity = new CmsContent();
|
||||
}
|
||||
BeanUtils.copyProperties(dto, contentEntity);
|
||||
CmsCatalog catalog = this.catalogService.getCatalog(dto.getCatalogId());
|
||||
contentEntity.setSiteId(catalog.getSiteId());
|
||||
contentEntity.setAttributes(ContentAttribute.convertInt(dto.getAttributes()));
|
||||
// 发布通道配置
|
||||
Map<String, Map<String, Object>> publishPipProps = new HashMap<>();
|
||||
dto.getPublishPipeProps().forEach(prop -> {
|
||||
publishPipProps.put(prop.getPipeCode(), prop.getProps());
|
||||
});
|
||||
contentEntity.setPublishPipeProps(publishPipProps);
|
||||
public IContent<?> readFrom(InputStream is) {
|
||||
ArticleDTO dto = JacksonUtils.from(is, ArticleDTO.class);
|
||||
return readFrom0(dto);
|
||||
}
|
||||
|
||||
private ArticleContent readFrom0(ArticleDTO dto) {
|
||||
// 内容基础信息
|
||||
CmsContent contentEntity = dto.convertToContentEntity(this.catalogService, this.contentService);
|
||||
// 文章扩展信息
|
||||
CmsArticleDetail extendEntity = new CmsArticleDetail();
|
||||
if (ContentOpType.UPDATE.equals(dto.getOpType())) {
|
||||
Optional<CmsArticleDetail> opt = this.articleService.dao().getOptById(contentEntity.getContentId());
|
||||
if (opt.isPresent()) {
|
||||
extendEntity = opt.get();
|
||||
}
|
||||
}
|
||||
BeanUtils.copyProperties(dto, extendEntity);
|
||||
|
||||
ArticleContent content = new ArticleContent();
|
||||
@ -148,9 +137,6 @@ public class ArticleContentType implements IContentType {
|
||||
|
||||
CmsArticleDetail extendEntity = this.articleService.dao().getById(contentId);
|
||||
vo = ArticleVO.newInstance(contentEntity, extendEntity);
|
||||
if (StringUtils.isNotEmpty(vo.getLogo())) {
|
||||
vo.setLogoSrc(InternalUrlUtils.getActualPreviewUrl(vo.getLogo()));
|
||||
}
|
||||
// 发布通道模板数据
|
||||
List<PublishPipeProp> publishPipeProps = this.publishPipeService.getPublishPipeProps(catalog.getSiteId(),
|
||||
PublishPipePropUseType.Content, contentEntity.getPublishPipeProps());
|
||||
|
||||
@ -103,7 +103,7 @@ public class ArticleCoreDataHandler implements ICoreDataHandler {
|
||||
data.setContentHtml(html.toString());
|
||||
articleService.dao().save(data);
|
||||
} catch (Exception e) {
|
||||
AsyncTaskManager.addErrMessage("导入文章数据失败:" + oldContentId);
|
||||
AsyncTaskManager.addErrMessage("导入文章数据`" + oldContentId + "`失败:" + e.getMessage());
|
||||
log.error("Import article detail failed: {}", oldContentId, e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,32 +13,37 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.chestnut.common.storage;
|
||||
package com.chestnut.article;
|
||||
|
||||
import java.util.List;
|
||||
/**
|
||||
* 文正正文文档格式
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
*/
|
||||
public interface IArticleBodyFormat {
|
||||
|
||||
public class StorageListResult<T> {
|
||||
String BEAN_PREFIX = "ArticleBodyFormat_";
|
||||
|
||||
private List<T> objects;
|
||||
|
||||
/**
|
||||
* 列举文件使用的continuationToken
|
||||
*/
|
||||
private String nextContinuationToken ;
|
||||
|
||||
public String getNextContinuationToken() {
|
||||
return nextContinuationToken;
|
||||
}
|
||||
/**
|
||||
* ID
|
||||
*/
|
||||
String getId();
|
||||
|
||||
public void setNextContinuationToken(String nextContinuationToken) {
|
||||
this.nextContinuationToken = nextContinuationToken;
|
||||
}
|
||||
/**
|
||||
* 名称
|
||||
*/
|
||||
String getName();
|
||||
|
||||
public List<T> getObjects() {
|
||||
return objects;
|
||||
}
|
||||
/**
|
||||
* 编辑器内容初始化处理
|
||||
*/
|
||||
default String initEditor(String contentHtml) {
|
||||
return contentHtml;
|
||||
}
|
||||
|
||||
public void setObjects(List<T> objects) {
|
||||
this.objects = objects;
|
||||
}
|
||||
/**
|
||||
* 文章正文内容发布预览处理
|
||||
*/
|
||||
String deal(String contentHtml, String publishPipeCode, boolean isPreview);
|
||||
}
|
||||
@ -16,8 +16,10 @@
|
||||
package com.chestnut.article.controller;
|
||||
|
||||
|
||||
import com.chestnut.article.IArticleBodyFormat;
|
||||
import com.chestnut.article.PublishPipeProp_UEditorCss;
|
||||
import com.chestnut.common.domain.R;
|
||||
import com.chestnut.common.i18n.I18nUtils;
|
||||
import com.chestnut.common.security.anno.Priv;
|
||||
import com.chestnut.common.security.web.BaseRestController;
|
||||
import com.chestnut.common.utils.StringUtils;
|
||||
@ -28,13 +30,16 @@ import com.chestnut.contentcore.service.ICatalogService;
|
||||
import com.chestnut.contentcore.service.IPublishPipeService;
|
||||
import com.chestnut.contentcore.service.ISiteService;
|
||||
import com.chestnut.system.security.AdminUserType;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@ -57,6 +62,8 @@ public class ArticleController extends BaseRestController {
|
||||
|
||||
private final IPublishPipeService publishPipeService;
|
||||
|
||||
private final List<IArticleBodyFormat> articleBodyFormatList;
|
||||
|
||||
@GetMapping("/ueditor_css")
|
||||
public R<?> getUEditorCss(@RequestParam Long catalogId) {
|
||||
CmsCatalog catalog = catalogService.getCatalog(catalogId);
|
||||
@ -73,5 +80,24 @@ public class ArticleController extends BaseRestController {
|
||||
});
|
||||
return R.ok(data);
|
||||
}
|
||||
|
||||
@GetMapping("/formats")
|
||||
public R<?> getArticleBodyFormats() {
|
||||
List<ArticleBodyFormat> list = this.articleBodyFormatList.stream().map(item -> {
|
||||
ArticleBodyFormat format = new ArticleBodyFormat();
|
||||
format.setId(item.getId());
|
||||
format.setName(I18nUtils.get(item.getName()));
|
||||
return format;
|
||||
}).toList();
|
||||
I18nUtils.replaceI18nFields(list);
|
||||
return R.ok(list);
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
static class ArticleBodyFormat {
|
||||
private String id;
|
||||
private String name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -113,27 +113,24 @@ public class ArticleApiController extends BaseRestController {
|
||||
return R.ok(List.of());
|
||||
}
|
||||
List<Long> contentIds = pageResult.getRecords().stream().map(CmsContent::getContentId).toList();
|
||||
Map<Long, CmsArticleDetail> articleDetails = this.articleService.dao().listByIds(contentIds)
|
||||
.stream().collect(Collectors.toMap(CmsArticleDetail::getContentId, c -> c));
|
||||
Map<Long, CmsArticleDetail> articleDetails = new HashMap<>();
|
||||
if (text) {
|
||||
articleDetails.putAll(this.articleService.dao().listByIds(contentIds)
|
||||
.stream().collect(Collectors.toMap(CmsArticleDetail::getContentId, c -> c)));
|
||||
}
|
||||
|
||||
Map<Long, CmsCatalog> loadedCatalogs = new HashMap<>();
|
||||
List<ArticleApiVO> list = new ArrayList<>();
|
||||
pageResult.getRecords().forEach(c -> {
|
||||
ArticleApiVO dto = ArticleApiVO.newInstance(c);
|
||||
CmsCatalog catalog = loadedCatalogs.get(c.getCatalogId());
|
||||
if (Objects.isNull(catalog)) {
|
||||
catalog = this.catalogService.getCatalog(c.getCatalogId());
|
||||
loadedCatalogs.put(catalog.getCatalogId(), catalog);
|
||||
ArticleApiVO vo = ArticleApiVO.newInstance(c, null);
|
||||
CmsCatalog catalog = this.catalogService.getCatalog(c.getCatalogId());
|
||||
vo.setCatalogName(catalog.getName());
|
||||
vo.setCatalogLink(catalogService.getCatalogLink(catalog, 1, publishPipeCode, preview));
|
||||
vo.setLink(this.contentService.getContentLink(c, 1, publishPipeCode, preview));
|
||||
vo.setLogoSrc(InternalUrlUtils.getActualUrl(c.getLogo(), publishPipeCode, preview));
|
||||
if (text && articleDetails.containsKey(c.getContentId())) {
|
||||
vo.setContentHtml(articleDetails.get(c.getContentId()).getContentHtml());
|
||||
}
|
||||
dto.setCatalogName(catalog.getName());
|
||||
dto.setCatalogLink(catalogService.getCatalogLink(catalog, 1, publishPipeCode, preview));
|
||||
dto.setLink(this.contentService.getContentLink(c, 1, publishPipeCode, preview));
|
||||
dto.setLogoSrc(InternalUrlUtils.getActualUrl(c.getLogo(), publishPipeCode, preview));
|
||||
CmsArticleDetail articleDetail = articleDetails.get(c.getContentId());
|
||||
if (Objects.nonNull(articleDetail)) {
|
||||
dto.setContentHtml(articleDetail.getContentHtml());
|
||||
}
|
||||
list.add(dto);
|
||||
list.add(vo);
|
||||
});
|
||||
return R.ok(list);
|
||||
}
|
||||
|
||||
@ -46,11 +46,6 @@ public class CmsArticleDetail implements IBackupable<BCmsArticleDetail> {
|
||||
* 站点ID
|
||||
*/
|
||||
private Long siteId;
|
||||
|
||||
/**
|
||||
* 正文详情(json)
|
||||
*/
|
||||
private String contentJson;
|
||||
|
||||
/**
|
||||
* 正文详情(html)
|
||||
@ -67,6 +62,11 @@ public class CmsArticleDetail implements IBackupable<BCmsArticleDetail> {
|
||||
*/
|
||||
private String downloadRemoteImage;
|
||||
|
||||
/**
|
||||
* 正文格式(图文混排,MARKDOWN)
|
||||
*/
|
||||
private String format;
|
||||
|
||||
@Override
|
||||
public BCmsArticleDetail toBackupEntity() {
|
||||
BCmsArticleDetail backupEntity = new BCmsArticleDetail();
|
||||
|
||||
@ -15,17 +15,12 @@
|
||||
*/
|
||||
package com.chestnut.article.domain.dto;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
|
||||
import com.chestnut.article.domain.CmsArticleDetail;
|
||||
import com.chestnut.common.utils.StringUtils;
|
||||
import com.chestnut.contentcore.domain.CmsContent;
|
||||
import com.chestnut.contentcore.domain.dto.ContentDTO;
|
||||
import com.chestnut.contentcore.fixed.dict.ContentAttribute;
|
||||
import com.chestnut.contentcore.util.InternalUrlUtils;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ -46,13 +41,14 @@ public class ArticleDTO extends ContentDTO {
|
||||
*/
|
||||
private String pageTitles;
|
||||
|
||||
public static ArticleDTO newInstance(CmsContent content, CmsArticleDetail articleDetail) {
|
||||
/**
|
||||
* 文档格式
|
||||
*/
|
||||
private String format;
|
||||
|
||||
public static ArticleDTO newInstance(CmsContent content, CmsArticleDetail articleDetail, boolean preview) {
|
||||
ArticleDTO dto = new ArticleDTO();
|
||||
BeanUtils.copyProperties(content, dto);
|
||||
dto.setAttributes(ContentAttribute.convertStr(content.getAttributes()));
|
||||
if (StringUtils.isNotEmpty(dto.getLogo())) {
|
||||
dto.setLogoSrc(InternalUrlUtils.getActualPreviewUrl(dto.getLogo()));
|
||||
}
|
||||
dto.initByContent(content, preview);
|
||||
BeanUtils.copyProperties(articleDetail, dto);
|
||||
return dto;
|
||||
}
|
||||
|
||||
@ -15,11 +15,14 @@
|
||||
*/
|
||||
package com.chestnut.article.domain.vo;
|
||||
|
||||
import com.chestnut.article.domain.CmsArticleDetail;
|
||||
import com.chestnut.contentcore.domain.CmsContent;
|
||||
import com.chestnut.contentcore.domain.vo.ContentApiVO;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* <TODO description class purpose>
|
||||
*
|
||||
@ -32,9 +35,12 @@ public class ArticleApiVO extends ContentApiVO {
|
||||
|
||||
private String contentHtml;
|
||||
|
||||
public static ArticleApiVO newInstance(CmsContent cmsContent) {
|
||||
public static ArticleApiVO newInstance(CmsContent cmsContent, CmsArticleDetail articleDetail) {
|
||||
ArticleApiVO vo = new ArticleApiVO();
|
||||
vo.copyProperties(cmsContent);
|
||||
vo.initByContent(cmsContent, false);
|
||||
if (Objects.nonNull(articleDetail)) {
|
||||
vo.setContentHtml(articleDetail.getContentHtml());
|
||||
}
|
||||
return vo;
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,20 +15,14 @@
|
||||
*/
|
||||
package com.chestnut.article.domain.vo;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
|
||||
import com.chestnut.article.domain.CmsArticleDetail;
|
||||
import com.chestnut.common.utils.StringUtils;
|
||||
import com.chestnut.contentcore.domain.CmsContent;
|
||||
import com.chestnut.contentcore.domain.vo.ContentVO;
|
||||
import com.chestnut.contentcore.fixed.dict.ContentAttribute;
|
||||
import com.chestnut.contentcore.util.InternalUrlUtils;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class ArticleVO extends ContentVO {
|
||||
@ -48,16 +42,20 @@ public class ArticleVO extends ContentVO {
|
||||
*/
|
||||
private String pageTitles;
|
||||
|
||||
/**
|
||||
* 文档格式
|
||||
*/
|
||||
private String format;
|
||||
|
||||
public static ArticleVO newInstance(CmsContent content, CmsArticleDetail articleDetail) {
|
||||
ArticleVO dto = new ArticleVO();
|
||||
BeanUtils.copyProperties(content, dto);
|
||||
dto.setAttributes(ContentAttribute.convertStr(content.getAttributes()));
|
||||
if (StringUtils.isNotEmpty(dto.getLogo())) {
|
||||
dto.setLogoSrc(InternalUrlUtils.getActualPreviewUrl(dto.getLogo()));
|
||||
}
|
||||
ArticleVO vo = new ArticleVO();
|
||||
vo.initByContent(content, true);
|
||||
if (Objects.nonNull(articleDetail)) {
|
||||
BeanUtils.copyProperties(articleDetail, dto);
|
||||
vo.setContentHtml(articleDetail.getContentHtml());
|
||||
vo.setDownloadRemoteImage(articleDetail.getDownloadRemoteImage());
|
||||
vo.setPageTitles(articleDetail.getPageTitles());
|
||||
vo.setFormat(articleDetail.getFormat());
|
||||
}
|
||||
return dto;
|
||||
return vo;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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.article.format;
|
||||
|
||||
import com.chestnut.article.ArticleUtils;
|
||||
import com.chestnut.article.IArticleBodyFormat;
|
||||
import com.chestnut.contentcore.util.InternalUrlUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 文章正文文档格式:富文本
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
*/
|
||||
@Component(IArticleBodyFormat.BEAN_PREFIX + ArticleBodyFormat_RichText.ID)
|
||||
public class ArticleBodyFormat_RichText implements IArticleBodyFormat {
|
||||
|
||||
public static final String ID = "RichText";
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "{ArticleBodyFormat.RichText}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String initEditor(String contentHtml) {
|
||||
return InternalUrlUtils.dealResourceInternalUrl(contentHtml);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String deal(String contentHtml, String publishPipeCode, boolean isPreview) {
|
||||
// 处理内容扩展模板占位符
|
||||
contentHtml = ArticleUtils.dealContentEx(contentHtml, publishPipeCode, isPreview);
|
||||
// 处理正文内部链接
|
||||
contentHtml = InternalUrlUtils.dealInternalUrl(contentHtml, publishPipeCode, isPreview);
|
||||
return contentHtml;
|
||||
}
|
||||
}
|
||||
@ -16,6 +16,7 @@
|
||||
package com.chestnut.article.listener;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.chestnut.article.IArticleBodyFormat;
|
||||
import com.chestnut.article.domain.BCmsArticleDetail;
|
||||
import com.chestnut.article.domain.CmsArticleDetail;
|
||||
import com.chestnut.article.domain.vo.ArticleVO;
|
||||
@ -24,13 +25,13 @@ import com.chestnut.common.async.AsyncTaskManager;
|
||||
import com.chestnut.contentcore.domain.CmsSite;
|
||||
import com.chestnut.contentcore.listener.event.AfterContentEditorInitEvent;
|
||||
import com.chestnut.contentcore.listener.event.BeforeSiteDeleteEvent;
|
||||
import com.chestnut.contentcore.util.InternalUrlUtils;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@ -81,7 +82,12 @@ public class ArticleListener {
|
||||
@EventListener
|
||||
public void afterContentEditorInit(AfterContentEditorInitEvent event) {
|
||||
if (event.getContentVO() instanceof ArticleVO vo) {
|
||||
vo.setContentHtml(InternalUrlUtils.dealResourceInternalUrl(vo.getContentHtml()));
|
||||
IArticleBodyFormat articleBodyFormat = articleService.getArticleBodyFormat(vo.getFormat());
|
||||
if (Objects.nonNull(articleBodyFormat)) {
|
||||
vo.setContentHtml(articleBodyFormat.initEditor(vo.getContentHtml()));
|
||||
} else {
|
||||
log.warn("Unsupported article body format: " + vo.getFormat());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.chestnut.article.service;
|
||||
|
||||
import com.chestnut.article.IArticleBodyFormat;
|
||||
import com.chestnut.article.dao.CmsArticleDetailDAO;
|
||||
import com.chestnut.common.db.mybatisplus.HasDAO;
|
||||
|
||||
@ -25,4 +26,5 @@ import com.chestnut.common.db.mybatisplus.HasDAO;
|
||||
* @email 190785909@qq.com
|
||||
*/
|
||||
public interface IArticleService extends HasDAO<CmsArticleDetailDAO> {
|
||||
IArticleBodyFormat getArticleBodyFormat(String format);
|
||||
}
|
||||
|
||||
@ -15,12 +15,15 @@
|
||||
*/
|
||||
package com.chestnut.article.service.impl;
|
||||
|
||||
import com.chestnut.article.IArticleBodyFormat;
|
||||
import com.chestnut.article.dao.CmsArticleDetailDAO;
|
||||
import com.chestnut.article.service.IArticleService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@ -28,8 +31,17 @@ public class ArticleServiceImpl implements IArticleService {
|
||||
|
||||
private final CmsArticleDetailDAO dao;
|
||||
|
||||
|
||||
private final Map<String, IArticleBodyFormat> articleBodyFormatMap;
|
||||
|
||||
@Override
|
||||
public CmsArticleDetailDAO dao() {
|
||||
return this.dao;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IArticleBodyFormat getArticleBodyFormat(String format) {
|
||||
return articleBodyFormatMap.get(IArticleBodyFormat.BEAN_PREFIX + format);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -15,12 +15,14 @@
|
||||
*/
|
||||
package com.chestnut.article.template.func;
|
||||
|
||||
import com.chestnut.article.ArticleUtils;
|
||||
import com.chestnut.article.IArticleBodyFormat;
|
||||
import com.chestnut.article.format.ArticleBodyFormat_RichText;
|
||||
import com.chestnut.article.service.IArticleService;
|
||||
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.Assert;
|
||||
import com.chestnut.common.utils.StringUtils;
|
||||
import com.chestnut.contentcore.util.InternalUrlUtils;
|
||||
import freemarker.core.Environment;
|
||||
import freemarker.template.SimpleScalar;
|
||||
import freemarker.template.TemplateModelException;
|
||||
@ -28,6 +30,7 @@ import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Freemarker模板自定义函数:处理Html文本内容中的内部链接
|
||||
@ -38,7 +41,13 @@ public class dealArticleBodyFunction extends AbstractFunc {
|
||||
|
||||
static final String FUNC_NAME = "dealArticleBody";
|
||||
|
||||
private static final String DESC = "{FREEMARKER.FUNC.DESC." + FUNC_NAME + "}";
|
||||
private static final String DESC = "{FREEMARKER.FUNC." + FUNC_NAME + ".DESC}";
|
||||
|
||||
private static final String ARG1_NAME = "{FREEMARKER.FUNC." + FUNC_NAME + ".Arg1.Name}";
|
||||
|
||||
private static final String ARG2_NAME = "{FREEMARKER.FUNC." + FUNC_NAME + ".Arg2.Name}";
|
||||
|
||||
private final IArticleService articleService;
|
||||
|
||||
@Override
|
||||
public String getFuncName() {
|
||||
@ -55,18 +64,33 @@ public class dealArticleBodyFunction extends AbstractFunc {
|
||||
if (args.length < 1) {
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
String format;
|
||||
if (args.length > 1) {
|
||||
String _format = ((SimpleScalar) args[1]).getAsString();
|
||||
if (StringUtils.isEmpty(_format)) {
|
||||
_format = ArticleBodyFormat_RichText.ID;
|
||||
}
|
||||
format = _format;
|
||||
} else {
|
||||
format = ArticleBodyFormat_RichText.ID;
|
||||
}
|
||||
TemplateContext context = FreeMarkerUtils.getTemplateContext(Environment.getCurrentEnvironment());
|
||||
SimpleScalar simpleScalar = (SimpleScalar) args[0];
|
||||
String contentHtml = simpleScalar.getAsString();
|
||||
// 处理内容扩展模板占位符
|
||||
contentHtml = ArticleUtils.dealContentEx(contentHtml, context.getPublishPipeCode(), context.isPreview());
|
||||
// 处理正文内部链接
|
||||
contentHtml = InternalUrlUtils.dealInternalUrl(contentHtml, context.getPublishPipeCode(), context.isPreview());
|
||||
IArticleBodyFormat articleBodyFormat = articleService.getArticleBodyFormat(format);
|
||||
Assert.notNull(articleBodyFormat, () -> new TemplateModelException("Unsupported article body format: " + format));
|
||||
if (Objects.isNull(articleBodyFormat)) {
|
||||
articleBodyFormat = articleService.getArticleBodyFormat(ArticleBodyFormat_RichText.ID);
|
||||
}
|
||||
contentHtml = articleBodyFormat.deal(contentHtml, context.getPublishPipeCode(), context.isPreview());
|
||||
return contentHtml;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FuncArg> getFuncArgs() {
|
||||
return List.of(new FuncArg("HTML文章正文内容", FuncArgType.String, true, null));
|
||||
return List.of(
|
||||
new FuncArg(ARG1_NAME, FuncArgType.String, true, null),
|
||||
new FuncArg(ARG2_NAME, FuncArgType.String, false, null, ArticleBodyFormat_RichText.ID)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,10 +17,13 @@ package com.chestnut.article.template.tag;
|
||||
|
||||
import com.chestnut.article.domain.CmsArticleDetail;
|
||||
import com.chestnut.article.mapper.CmsArticleDetailMapper;
|
||||
import com.chestnut.common.annotation.XComment;
|
||||
import com.chestnut.common.staticize.FreeMarkerUtils;
|
||||
import com.chestnut.common.staticize.StaticizeConstants;
|
||||
import com.chestnut.common.staticize.core.TemplateContext;
|
||||
import com.chestnut.common.staticize.enums.TagAttrDataType;
|
||||
import com.chestnut.common.staticize.exception.DuplicatePageFlagException;
|
||||
import com.chestnut.common.staticize.exception.PageIndexOutOfBoundsException;
|
||||
import com.chestnut.common.staticize.tag.AbstractTag;
|
||||
import com.chestnut.common.staticize.tag.TagAttr;
|
||||
import com.chestnut.common.utils.StringUtils;
|
||||
@ -30,35 +33,36 @@ import com.chestnut.contentcore.mapper.CmsContentMapper;
|
||||
import freemarker.core.Environment;
|
||||
import freemarker.template.TemplateException;
|
||||
import freemarker.template.TemplateModel;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.apache.commons.collections4.MapUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class CmsArticleTag extends AbstractTag {
|
||||
|
||||
public static final String TAG_NAME = "cms_article";
|
||||
public final static String NAME = "{FREEMARKER.TAG.NAME." + TAG_NAME + "}";
|
||||
public final static String DESC = "{FREEMARKER.TAG.DESC." + TAG_NAME + "}";
|
||||
public final static String NAME = "{FREEMARKER.TAG." + TAG_NAME + ".NAME}";
|
||||
public final static String DESC = "{FREEMARKER.TAG." + TAG_NAME + ".DESC}";
|
||||
public final static String ATTR_USAGE_CONTENT_ID = "{FREEMARKER.TAG." + TAG_NAME + ".contentId}";
|
||||
public final static String ATTR_USAGE_PAGE = "{FREEMARKER.TAG." + TAG_NAME + ".page}";
|
||||
|
||||
public static final String TagAttr_ContentId = "contentId";
|
||||
|
||||
public static final String TagAttr_Page = "page";
|
||||
public static final String ATTR_CONTENT_ID = "contentId";
|
||||
public static final String ATTR_PAGE = "page";
|
||||
|
||||
public static final String TemplateVariable_ArticleContent = "ArticleContent";
|
||||
|
||||
// CKEditor5: <div class="page-break" style="page-break-after:always;"><span style="display:none;"> </span></div>
|
||||
// private static final String PAGE_BREAK_SPLITER = "<div[^>]+class=['\"]page-break['\"].*?</div>";
|
||||
private static final String PAGE_BREAK_SPLITER = "__XY_UEDITOR_PAGE_BREAK__";
|
||||
|
||||
|
||||
private final CmsContentMapper contentMapper;
|
||||
|
||||
private final CmsArticleDetailMapper articleMapper;
|
||||
@ -66,16 +70,16 @@ public class CmsArticleTag extends AbstractTag {
|
||||
@Override
|
||||
public List<TagAttr> getTagAttrs() {
|
||||
List<TagAttr> tagAttrs = new ArrayList<>();
|
||||
tagAttrs.add(new TagAttr(TagAttr_ContentId, true, TagAttrDataType.INTEGER, "文章内容ID"));
|
||||
tagAttrs.add(new TagAttr(TagAttr_Page, false, TagAttrDataType.BOOLEAN, "是否分页,默认false"));
|
||||
tagAttrs.add(new TagAttr(ATTR_CONTENT_ID, true, TagAttrDataType.INTEGER, ATTR_USAGE_CONTENT_ID));
|
||||
tagAttrs.add(new TagAttr(ATTR_PAGE, false, TagAttrDataType.BOOLEAN, ATTR_USAGE_PAGE, Boolean.FALSE.toString()));
|
||||
return tagAttrs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, TemplateModel> execute0(Environment env, Map<String, String> attrs)
|
||||
throws TemplateException, IOException {
|
||||
String contentHtml = null;
|
||||
long contentId = MapUtils.getLongValue(attrs, TagAttr_ContentId, 0);
|
||||
throws TemplateException {
|
||||
String contentHtml;
|
||||
long contentId = MapUtils.getLongValue(attrs, ATTR_CONTENT_ID, 0);
|
||||
if (contentId <= 0) {
|
||||
throw new TemplateException("Invalid contentId: " + contentId, env);
|
||||
}
|
||||
@ -92,24 +96,32 @@ public class CmsArticleTag extends AbstractTag {
|
||||
}
|
||||
contentHtml = articleDetail.getContentHtml();
|
||||
TemplateContext context = FreeMarkerUtils.getTemplateContext(env);
|
||||
boolean page = MapUtils.getBooleanValue(attrs, TagAttr_Page, false);
|
||||
boolean page = MapUtils.getBooleanValue(attrs, ATTR_PAGE, false);
|
||||
if (page) {
|
||||
if (context.isPaged()) {
|
||||
throw new TemplateException("分页标识已被其他标签激活", env);
|
||||
throw new DuplicatePageFlagException(env);
|
||||
}
|
||||
context.setPaged(true);
|
||||
|
||||
String[] pageContents = contentHtml.split(PAGE_BREAK_SPLITER);
|
||||
if (context.getPageIndex() > pageContents.length) {
|
||||
throw new TemplateException(StringUtils.messageFormat("文章内容分页越界:{0}, 最大页码:{1}。", context.getPageIndex(),
|
||||
pageContents.length), env);
|
||||
throw new PageIndexOutOfBoundsException(context.getPageIndex(), pageContents.length, env);
|
||||
}
|
||||
context.setPageTotal(pageContents.length);
|
||||
env.setGlobalVariable(StaticizeConstants.TemplateVariable_PageTotal,
|
||||
this.wrap(env, context.getPageTotal()));
|
||||
contentHtml = pageContents[context.getPageIndex() - 1];
|
||||
}
|
||||
return Map.of(TemplateVariable_ArticleContent, this.wrap(env, contentHtml));
|
||||
ArticleTagData data = new ArticleTagData(articleDetail.getFormat(), contentHtml);
|
||||
return Map.of(
|
||||
TemplateVariable_ArticleContent, this.wrap(env, contentHtml), // 兼容历史版本保留ArticleContent
|
||||
StaticizeConstants.TemplateVariable_Data, this.wrap(env, data)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<ArticleTagData> getDataClass() {
|
||||
return ArticleTagData.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -126,4 +138,21 @@ public class CmsArticleTag extends AbstractTag {
|
||||
public String getDescription() {
|
||||
return DESC;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
public static class ArticleTagData {
|
||||
|
||||
@XComment("文章正文格式")
|
||||
private String Format;
|
||||
|
||||
@XComment("文章正文")
|
||||
private String ArticleContent;
|
||||
|
||||
public ArticleTagData(String format, String articleContent) {
|
||||
this.Format = format;
|
||||
this.ArticleContent = articleContent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,6 +2,13 @@
|
||||
CMS.CONTENTCORE.CONTENT_TYPE.article=文章
|
||||
|
||||
# 模板freemarker
|
||||
FREEMARKER.TAG.NAME.cms_article=文章正文数据标签
|
||||
FREEMARKER.TAG.DESC.cms_article=获取文章正文数据,标签内使用${ArticleContent}获取正文详情
|
||||
FREEMARKER.FUNC.DESC.dealArticleBody=文章正文处理函数,主要用来处理文章内容中的内部链接和扩展模板占位符
|
||||
FREEMARKER.TAG.cms_article.NAME=文章正文数据标签
|
||||
FREEMARKER.TAG.cms_article.DESC=获取文章正文数据,标签内使用`${ArticleContent}`获取正文详情
|
||||
FREEMARKER.TAG.cms_article.contentId=文章ID
|
||||
FREEMARKER.TAG.cms_article.page=是否分頁
|
||||
FREEMARKER.FUNC.dealArticleBody.DESC=文章正文处理函数,主要用来处理文章内容中的内部链接和扩展模板占位符
|
||||
FREEMARKER.FUNC.dealArticleBody.Arg1.Name=文章正文内容
|
||||
FREEMARKER.FUNC.dealArticleBody.Arg2.Name=文章正文格式
|
||||
|
||||
# 固定字典项
|
||||
ArticleBodyFormat.RichText=富文本
|
||||
@ -2,6 +2,12 @@
|
||||
CMS.CONTENTCORE.CONTENT_TYPE.article=Article
|
||||
|
||||
# 模板freemarker
|
||||
FREEMARKER.TAG.NAME.cms_article=Article body tag
|
||||
FREEMARKER.TAG.DESC.cms_article=Fetch article body details, use "${ArticleContent}" in tag to get body text.
|
||||
FREEMARKER.FUNC.DESC.dealArticleBody=Article body deal function
|
||||
FREEMARKER.TAG.cms_article.NAME=Article body tag
|
||||
FREEMARKER.TAG.cms_article.DESC=Fetch article body details, use `${ArticleContent}` in tag to get body text.
|
||||
FREEMARKER.TAG.cms_article.contentId=Article content id.
|
||||
FREEMARKER.TAG.cms_article.page=Pageable
|
||||
FREEMARKER.FUNC.dealArticleBody.DESC=Article body deal function
|
||||
FREEMARKER.FUNC.dealArticleBody.Arg1.Name=Article body text
|
||||
FREEMARKER.FUNC.dealArticleBody.Arg2.Name=Article body format
|
||||
|
||||
ArticleBodyFormat.RichText=Rich Text
|
||||
@ -2,6 +2,12 @@
|
||||
CMS.CONTENTCORE.CONTENT_TYPE.article=文章
|
||||
|
||||
# 模板freemarker
|
||||
FREEMARKER.TAG.NAME.cms_article=文章正文數據標籤
|
||||
FREEMARKER.TAG.DESC.cms_article=獲取文章正文數據,標籤內使用${ArticleContent}獲取正文詳情
|
||||
FREEMARKER.FUNC.DESC.dealArticleBody=文章正文處理函數,主要用來處理文章內容中的內部連結和擴展模板佔位符
|
||||
FREEMARKER.TAG.cms_article.NAME=文章正文數據標籤
|
||||
FREEMARKER.TAG.cms_article.DESC=獲取文章正文數據,標籤內使用`${ArticleContent}`獲取正文詳情
|
||||
FREEMARKER.TAG.cms_article.contentId=文章ID
|
||||
FREEMARKER.TAG.cms_article.page=是否分頁
|
||||
FREEMARKER.FUNC.dealArticleBody.DESC=文章正文處理函數,主要用來處理文章內容中的內部連結和擴展模板佔位符
|
||||
FREEMARKER.FUNC.dealArticleBody.Arg1.Name=文章正文內容
|
||||
FREEMARKER.FUNC.dealArticleBody.Arg2.Name=文章正文格式
|
||||
|
||||
ArticleBodyFormat.RichText=富文本
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<artifactId>chestnut-cms</artifactId>
|
||||
<version>1.5.0</version>
|
||||
<version>1.5.1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>chestnut-cms-block</artifactId>
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<artifactId>chestnut-cms</artifactId>
|
||||
<version>1.5.0</version>
|
||||
<version>1.5.1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>chestnut-cms-comment</artifactId>
|
||||
|
||||
@ -42,8 +42,14 @@ import java.util.stream.Collectors;
|
||||
public class CmsCommentTag extends AbstractListTag {
|
||||
|
||||
public final static String TAG_NAME = "cms_comment";
|
||||
public final static String NAME = "{FREEMARKER.TAG.NAME." + TAG_NAME + "}";
|
||||
public final static String DESC = "{FREEMARKER.TAG.DESC." + TAG_NAME + "}";
|
||||
public final static String NAME = "{FREEMARKER.TAG." + TAG_NAME + ".NAME}";
|
||||
public final static String DESC = "{FREEMARKER.TAG." + TAG_NAME + ".DESC}";
|
||||
public final static String ATTR_USAGE_UID = "{FREEMARKER.TAG." + TAG_NAME + ".uid}";
|
||||
public final static String ATTR_USAGE_TYPE = "{FREEMARKER.TAG." + TAG_NAME + ".type}";
|
||||
|
||||
public final static String ATTR_UID = "uid";
|
||||
public final static String ATTR_TYPE = "type";
|
||||
|
||||
|
||||
private final ICommentService commentService;
|
||||
|
||||
@ -52,15 +58,15 @@ public class CmsCommentTag extends AbstractListTag {
|
||||
@Override
|
||||
public List<TagAttr> getTagAttrs() {
|
||||
List<TagAttr> tagAttrs = super.getTagAttrs();
|
||||
tagAttrs.add(new TagAttr("uid", true, TagAttrDataType.INTEGER, "用户ID"));
|
||||
tagAttrs.add(new TagAttr("type", false, TagAttrDataType.STRING, "来源类型", CommentConsts.COMMENT_SOURCE_TYPE));
|
||||
tagAttrs.add(new TagAttr(ATTR_UID, true, TagAttrDataType.INTEGER, ATTR_USAGE_UID));
|
||||
tagAttrs.add(new TagAttr(ATTR_TYPE, false, TagAttrDataType.STRING, ATTR_USAGE_TYPE, CommentConsts.COMMENT_SOURCE_TYPE));
|
||||
return tagAttrs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TagPageData prepareData(Environment env, Map<String, String> attrs, boolean page, int size, int pageIndex) throws TemplateException {
|
||||
long uid = MapUtils.getLongValue(attrs, "uid");
|
||||
String sourceType = attrs.get("type");
|
||||
long uid = MapUtils.getLongValue(attrs, ATTR_UID);
|
||||
String sourceType = attrs.get(ATTR_TYPE);
|
||||
|
||||
Page<Comment> pageResult = this.commentService.lambdaQuery()
|
||||
.eq(Comment::getSourceType, sourceType)
|
||||
@ -87,6 +93,11 @@ public class CmsCommentTag extends AbstractListTag {
|
||||
return TagPageData.of(pageResult.getRecords(), pageResult.getTotal());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Comment> getDataClass() {
|
||||
return Comment.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTagName() {
|
||||
return TAG_NAME;
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
# freemarker模板标签
|
||||
FREEMARKER.TAG.NAME.cms_comment=评论列表标签
|
||||
FREEMARKER.TAG.DESC.cms_comment=获取评论数据列表,内嵌<#list DataList as comment>${comment.name}</#list>遍历数据
|
||||
FREEMARKER.TAG.cms_comment.NAME=评论列表标签
|
||||
FREEMARKER.TAG.cms_comment.DESC=获取评论数据列表,内嵌`<#list DataList as comment>${comment.name}</#list>`遍历数据
|
||||
FREEMARKER.TAG.cms_comment.uid=用户ID
|
||||
FREEMARKER.TAG.cms_comment.type=来源类型
|
||||
@ -1,3 +1,5 @@
|
||||
# freemarker模板标签
|
||||
FREEMARKER.TAG.NAME.cms_comment=Comment list tag
|
||||
FREEMARKER.TAG.DESC.cms_comment=Fetch comment list, use <#list> in tag like "<#list DataList as comment>${comment.title}</#list>" to walk through the list of comments.
|
||||
FREEMARKER.TAG.cms_comment.NAME=Comment list tag
|
||||
FREEMARKER.TAG.cms_comment.DESC=Fetch comment list, use `<#list>` in tag like `<#list DataList as comment>${comment.title}</#list>` to walk through the list of comments.
|
||||
FREEMARKER.TAG.cms_comment.uid=User id
|
||||
FREEMARKER.TAG.cms_comment.type=Owner type
|
||||
@ -1,3 +1,5 @@
|
||||
# freemarker模板標籤
|
||||
FREEMARKER.TAG.NAME.cms_comment=評論列表標籤
|
||||
FREEMARKER.TAG.DESC.cms_comment=獲取評論數據列表,內嵌<#list DataList as comment>${comment.name}</#list>遍曆數據
|
||||
FREEMARKER.TAG.cms_comment.NAME=評論列表標籤
|
||||
FREEMARKER.TAG.cms_comment.DESC=獲取評論數據列表,內嵌`<#list DataList as comment>${comment.name}</#list>`遍曆數據
|
||||
FREEMARKER.TAG.cms_comment.uid=用戶ID
|
||||
FREEMARKER.TAG.cms_comment.type=來源類型
|
||||
|
||||
@ -7,19 +7,13 @@
|
||||
<parent>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<artifactId>chestnut-cms</artifactId>
|
||||
<version>1.5.0</version>
|
||||
<version>1.5.1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>chestnut-cms-contentcore</artifactId>
|
||||
<description>内容核心</description>
|
||||
|
||||
<dependencies>
|
||||
<!-- 图片处理工具库 -->
|
||||
<dependency>
|
||||
<groupId>net.coobird</groupId>
|
||||
<artifactId>thumbnailator</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.chestnut</groupId>
|
||||
<artifactId>chestnut-search</artifactId>
|
||||
|
||||
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* 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.cache;
|
||||
|
||||
import com.chestnut.common.redis.IMonitoredCache;
|
||||
import com.chestnut.common.redis.RedisCache;
|
||||
import com.chestnut.contentcore.config.CMSConfig;
|
||||
import com.chestnut.contentcore.domain.CmsCatalog;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* CatalogMonitoredCache
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
*/
|
||||
@Component(IMonitoredCache.BEAN_PREFIX + CatalogMonitoredCache.ID)
|
||||
@RequiredArgsConstructor
|
||||
public class CatalogMonitoredCache implements IMonitoredCache<CmsCatalog> {
|
||||
|
||||
public static final String ID = "Catalog";
|
||||
|
||||
private static final String CACHE_PREFIX = CMSConfig.CachePrefix + "catalog:";
|
||||
|
||||
private final RedisCache redisCache;
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCacheName() {
|
||||
return "{MONITORED.CACHE.CATALOG}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCacheKey() {
|
||||
return CACHE_PREFIX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CmsCatalog getCache(String cacheKey) {
|
||||
return redisCache.getCacheObject(cacheKey, CmsCatalog.class);
|
||||
}
|
||||
|
||||
private String cacheKeyById(Long catalogId) {
|
||||
return CACHE_PREFIX + "id:" + catalogId;
|
||||
}
|
||||
|
||||
private String cacheKeyByAlias(Long siteId, String alias) {
|
||||
return CACHE_PREFIX + "alias:" + siteId + ":" + alias;
|
||||
}
|
||||
|
||||
public CmsCatalog getCacheById(Long catalogId) {
|
||||
return redisCache.getCacheObject(cacheKeyById(catalogId), CmsCatalog.class);
|
||||
}
|
||||
|
||||
public CmsCatalog getCacheById(Long catalogId, Supplier<CmsCatalog> supplier) {
|
||||
return redisCache.getCacheObject(cacheKeyById(catalogId), CmsCatalog.class, supplier);
|
||||
}
|
||||
|
||||
public CmsCatalog getCacheByAlias(Long siteId, String alias) {
|
||||
return redisCache.getCacheObject(cacheKeyByAlias(siteId, alias), CmsCatalog.class);
|
||||
}
|
||||
|
||||
public CmsCatalog getCacheByAlias(Long siteId, String alias, Supplier<CmsCatalog> supplier) {
|
||||
return redisCache.getCacheObject(cacheKeyByAlias(siteId, alias), CmsCatalog.class, supplier);
|
||||
}
|
||||
|
||||
public void clear(CmsCatalog catalog) {
|
||||
this.redisCache.deleteObject(cacheKeyById(catalog.getCatalogId()));
|
||||
this.redisCache.deleteObject(cacheKeyByAlias(catalog.getSiteId(), catalog.getAlias()));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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.cache;
|
||||
|
||||
import com.chestnut.common.redis.IMonitoredCache;
|
||||
import com.chestnut.common.redis.RedisCache;
|
||||
import com.chestnut.contentcore.config.CMSConfig;
|
||||
import com.chestnut.contentcore.domain.CmsPageWidget;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* PageWidgetMonitoredCache
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
*/
|
||||
@Component(IMonitoredCache.BEAN_PREFIX + PageWidgetMonitoredCache.ID)
|
||||
@RequiredArgsConstructor
|
||||
public class PageWidgetMonitoredCache implements IMonitoredCache<CmsPageWidget> {
|
||||
|
||||
public static final String ID = "PageWidget";
|
||||
|
||||
private static final String CACHE_PREFIX = CMSConfig.CachePrefix + "pagewidget:";
|
||||
|
||||
private final RedisCache redisCache;
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCacheName() {
|
||||
return "{MONITORED.CACHE.PAGE_WIDGET}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public CmsPageWidget getCache(String cacheKey) {
|
||||
return redisCache.getCacheObject(cacheKey, CmsPageWidget.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCacheKey() {
|
||||
return CACHE_PREFIX;
|
||||
}
|
||||
|
||||
public CmsPageWidget getCache(Long siteId, String code, Supplier<CmsPageWidget> supplier) {
|
||||
return redisCache.getCacheObject(CACHE_PREFIX + siteId + ":" + code, CmsPageWidget.class, supplier);
|
||||
}
|
||||
|
||||
public void clear(CmsPageWidget pageWidget) {
|
||||
this.redisCache.deleteObject(CACHE_PREFIX + pageWidget.getSiteId() + ":" + pageWidget.getCode());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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.cache;
|
||||
|
||||
import com.chestnut.common.redis.IMonitoredCache;
|
||||
import com.chestnut.common.redis.RedisCache;
|
||||
import com.chestnut.contentcore.config.CMSConfig;
|
||||
import com.chestnut.contentcore.domain.CmsSite;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* SiteMonitoredCache
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
*/
|
||||
@Component(IMonitoredCache.BEAN_PREFIX + SiteMonitoredCache.ID)
|
||||
@RequiredArgsConstructor
|
||||
public class SiteMonitoredCache implements IMonitoredCache<CmsSite> {
|
||||
|
||||
public static final String ID = "Site";
|
||||
|
||||
private static final String CACHE_PREFIX = CMSConfig.CachePrefix + "site:";
|
||||
|
||||
private final RedisCache redisCache;
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCacheName() {
|
||||
return "{MONITORED.CACHE.SITE}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public CmsSite getCache(String cacheKey) {
|
||||
return redisCache.getCacheObject(cacheKey, CmsSite.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCacheKey() {
|
||||
return CACHE_PREFIX;
|
||||
}
|
||||
|
||||
public CmsSite getCache(Long siteId, Supplier<CmsSite> supplier) {
|
||||
return redisCache.getCacheObject(CACHE_PREFIX + siteId, CmsSite.class, supplier);
|
||||
}
|
||||
|
||||
public void clear(long siteId) {
|
||||
this.redisCache.deleteObject(CACHE_PREFIX + siteId);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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.cache;
|
||||
|
||||
import com.chestnut.common.redis.IMonitoredCache;
|
||||
import com.chestnut.common.redis.RedisCache;
|
||||
import com.chestnut.contentcore.config.CMSConfig;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* TemplateMonitoredCache
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
*/
|
||||
@Component(IMonitoredCache.BEAN_PREFIX + TemplateMonitoredCache.ID)
|
||||
@RequiredArgsConstructor
|
||||
public class TemplateMonitoredCache implements IMonitoredCache<String> {
|
||||
|
||||
public static final String ID = "Template";
|
||||
|
||||
private static final String CACHE_PREFIX = CMSConfig.CachePrefix + "template:";
|
||||
|
||||
private final RedisCache redisCache;
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCacheName() {
|
||||
return "{MONITORED.CACHE.TEMPLATE}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCache(String cacheKey) {
|
||||
return redisCache.getCacheObject(cacheKey, String.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCacheKey() {
|
||||
return CACHE_PREFIX;
|
||||
}
|
||||
|
||||
public String getCache(String templateKey, Supplier<String> supplier) {
|
||||
return redisCache.getCacheObject(CACHE_PREFIX + templateKey, String.class, supplier);
|
||||
}
|
||||
|
||||
public void clear(String templateKey) {
|
||||
this.redisCache.deleteObject(CACHE_PREFIX + templateKey);
|
||||
}
|
||||
|
||||
public void setCache(String templateKey, String staticContent, int timeout, TimeUnit timeUnit) {
|
||||
redisCache.setCacheObject(CACHE_PREFIX + templateKey, staticContent, timeout, timeUnit);
|
||||
}
|
||||
}
|
||||
@ -69,10 +69,7 @@ public class CMSConfig implements WebMvcConfigurer {
|
||||
if (StringUtils.isEmpty(RESOURCE_ROOT)) {
|
||||
RESOURCE_ROOT = SpringUtils.getAppParentDirectory() + "/wwwroot_release/";
|
||||
}
|
||||
RESOURCE_ROOT = FileExUtils.normalizePath(RESOURCE_ROOT);
|
||||
if (!RESOURCE_ROOT.endsWith("/")) {
|
||||
RESOURCE_ROOT += "/";
|
||||
}
|
||||
RESOURCE_ROOT = StringUtils.appendIfMissing(FileExUtils.normalizePath(RESOURCE_ROOT), "/");
|
||||
FileExUtils.mkdirs(RESOURCE_ROOT);
|
||||
properties.setResourceRoot(RESOURCE_ROOT);
|
||||
log.info("ResourceRoot: " + RESOURCE_ROOT);
|
||||
@ -116,7 +113,7 @@ public class CMSConfig implements WebMvcConfigurer {
|
||||
public void resetCache() {
|
||||
if (this.properties.getResetCache()) {
|
||||
Collection<String> keys = this.redisCache.keys(this.properties.getCacheName() + "*");
|
||||
this.redisCache.deleteObject(keys);
|
||||
this.redisCache.deleteObjects(keys);
|
||||
log.info("Clear redis caches with prefix `{}`", this.properties.getCacheName());
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,11 +16,13 @@
|
||||
package com.chestnut.contentcore.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaMode;
|
||||
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
|
||||
import com.chestnut.common.async.AsyncTask;
|
||||
import com.chestnut.common.async.AsyncTaskManager;
|
||||
import com.chestnut.common.domain.R;
|
||||
import com.chestnut.common.domain.TreeNode;
|
||||
import com.chestnut.common.exception.CommonErrorCode;
|
||||
import com.chestnut.common.extend.annotation.XssIgnore;
|
||||
import com.chestnut.common.i18n.I18nUtils;
|
||||
import com.chestnut.common.log.annotation.Log;
|
||||
import com.chestnut.common.log.enums.BusinessType;
|
||||
@ -52,6 +54,7 @@ import com.chestnut.contentcore.util.SiteUtils;
|
||||
import com.chestnut.system.security.AdminUserType;
|
||||
import com.chestnut.system.security.StpAdminUtil;
|
||||
import com.chestnut.system.validator.LongId;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@ -177,14 +180,13 @@ public class CatalogController extends BaseRestController {
|
||||
@DeleteMapping("/{catalogId}")
|
||||
public R<String> deleteCatalog(@PathVariable("catalogId") @LongId Long catalogId) {
|
||||
LoginUser operator = StpAdminUtil.getLoginUser();
|
||||
AsyncTask task = new AsyncTask() {
|
||||
AsyncTask task = new AsyncTask("Catalog-" + catalogId) {
|
||||
|
||||
@Override
|
||||
public void run0() {
|
||||
catalogService.deleteCatalog(catalogId, operator);
|
||||
}
|
||||
};
|
||||
task.setTaskId("DeleteCatalog_" + catalogId);
|
||||
this.asyncTaskManager.execute(task);
|
||||
return R.ok(task.getTaskId());
|
||||
}
|
||||
@ -282,6 +284,7 @@ public class CatalogController extends BaseRestController {
|
||||
/**
|
||||
* 保存栏目扩展配置
|
||||
*/
|
||||
@XssIgnore
|
||||
@Priv(type = AdminUserType.TYPE, value = "Catalog:Edit:${#catalogId}")
|
||||
@Log(title = "栏目扩展", businessType = BusinessType.UPDATE, isSaveRequestData = false)
|
||||
@PutMapping("/extends/{catalogId}")
|
||||
@ -376,4 +379,48 @@ public class CatalogController extends BaseRestController {
|
||||
}
|
||||
return R.ok(Map.of("alias", alias, "path", path));
|
||||
}
|
||||
|
||||
@Priv(type = AdminUserType.TYPE)
|
||||
@GetMapping("/tree")
|
||||
public R<String> getCatalogTree(@RequestParam Long catalogId, HttpServletRequest request) {
|
||||
CmsSite site = siteService.getCurrentSite(request);
|
||||
CmsCatalog parent = null;
|
||||
if (IdUtils.validate(catalogId)) {
|
||||
parent = catalogService.getCatalog(catalogId);
|
||||
}
|
||||
LambdaQueryChainWrapper<CmsCatalog> q = catalogService.lambdaQuery()
|
||||
.select(CmsCatalog::getName, CmsCatalog::getAncestors, CmsCatalog::getTreeLevel)
|
||||
.eq(CmsCatalog::getSiteId, site.getSiteId());
|
||||
if (Objects.nonNull(parent)) {
|
||||
q.likeRight(CmsCatalog::getAncestors, parent.getAncestors());
|
||||
}
|
||||
List<CmsCatalog> list = q.list();
|
||||
list.sort(Comparator.comparing(CmsCatalog::getAncestors));
|
||||
StringBuilder sb = new StringBuilder();
|
||||
list.forEach(catalog -> {
|
||||
String prefix = StringUtils.leftPad("", (catalog.getTreeLevel() -1) * 2);
|
||||
sb.append(prefix).append(catalog.getName()).append(StringUtils.LF);
|
||||
});
|
||||
return R.ok(sb.toString());
|
||||
}
|
||||
|
||||
@Priv(type = AdminUserType.TYPE, value = "Catalog:Edit:${#catalogId}")
|
||||
@Log(title = "清空", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/clear")
|
||||
public R<String> clearCatalog(@RequestBody ClearCatalogDTO dto) {
|
||||
LoginUser operator = StpAdminUtil.getLoginUser();
|
||||
dto.setOperator(operator);
|
||||
AsyncTask task = catalogService.clearCatalog(dto);
|
||||
return R.ok(task.getTaskId());
|
||||
}
|
||||
|
||||
@Priv(type = AdminUserType.TYPE, value = "Catalog:Edit:${#catalogId}")
|
||||
@Log(title = "合并", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/merge")
|
||||
public R<String> mergeCatalog(@RequestBody MergeCatalogDTO dto) {
|
||||
LoginUser operator = StpAdminUtil.getLoginUser();
|
||||
dto.setOperator(operator);
|
||||
AsyncTask task = catalogService.mergeCatalogs(dto);
|
||||
return R.ok(task.getTaskId());
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,7 +32,6 @@ import com.chestnut.common.utils.ServletUtils;
|
||||
import com.chestnut.common.utils.StringUtils;
|
||||
import com.chestnut.contentcore.core.IContent;
|
||||
import com.chestnut.contentcore.core.IContentType;
|
||||
import com.chestnut.contentcore.core.impl.InternalDataType_Content;
|
||||
import com.chestnut.contentcore.domain.CmsCatalog;
|
||||
import com.chestnut.contentcore.domain.CmsContent;
|
||||
import com.chestnut.contentcore.domain.CmsSite;
|
||||
@ -50,7 +49,6 @@ import com.chestnut.contentcore.user.preference.IncludeChildContentPreference;
|
||||
import com.chestnut.contentcore.user.preference.ShowContentSubTitlePreference;
|
||||
import com.chestnut.contentcore.util.CmsPrivUtils;
|
||||
import com.chestnut.contentcore.util.ContentCoreUtils;
|
||||
import com.chestnut.contentcore.util.InternalUrlUtils;
|
||||
import com.chestnut.system.permission.PermissionUtils;
|
||||
import com.chestnut.system.security.AdminUserType;
|
||||
import com.chestnut.system.security.StpAdminUtil;
|
||||
@ -59,7 +57,6 @@ import freemarker.template.TemplateException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
@ -67,7 +64,6 @@ import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
@ -137,15 +133,7 @@ public class ContentController extends BaseRestController {
|
||||
q.orderByDesc(CmsContent::getTopFlag).orderByDesc(CmsContent::getSortFlag);
|
||||
}
|
||||
Page<CmsContent> page = q.page(new Page<>(pr.getPageNumber(), pr.getPageSize(), true));
|
||||
List<ListContentVO> list = new ArrayList<>();
|
||||
page.getRecords().forEach(content -> {
|
||||
ListContentVO vo = new ListContentVO();
|
||||
BeanUtils.copyProperties(content, vo);
|
||||
vo.setLogoSrc(InternalUrlUtils.getActualPreviewUrl(content.getLogo()));
|
||||
vo.setAttributes(ContentAttribute.convertStr(content.getAttributes()));
|
||||
vo.setInternalUrl(InternalUrlUtils.getInternalUrl(InternalDataType_Content.ID, content.getContentId()));
|
||||
list.add(vo);
|
||||
});
|
||||
List<ListContentVO> list = page.getRecords().stream().map(ListContentVO::newInstance).toList();
|
||||
return this.bindDataTable(list, (int) page.getTotal());
|
||||
}
|
||||
|
||||
@ -171,7 +159,7 @@ public class ContentController extends BaseRestController {
|
||||
throws IOException {
|
||||
IContentType ct = ContentCoreUtils.getContentType(contentType);
|
||||
|
||||
IContent<?> content = ct.readRequest(request);
|
||||
IContent<?> content = ct.readFrom(request.getInputStream());
|
||||
content.setOperator(StpAdminUtil.getLoginUser());
|
||||
PermissionUtils.checkPermission(CatalogPrivItem.AddContent.getPermissionKey(content.getCatalogId()),
|
||||
content.getOperator());
|
||||
@ -187,7 +175,7 @@ public class ContentController extends BaseRestController {
|
||||
throws IOException {
|
||||
IContentType ct = ContentCoreUtils.getContentType(contentType);
|
||||
|
||||
IContent<?> content = ct.readRequest(request);
|
||||
IContent<?> content = ct.readFrom(request.getInputStream());
|
||||
content.setOperator(StpAdminUtil.getLoginUser());
|
||||
PermissionUtils.checkPermission(CatalogPrivItem.EditContent.getPermissionKey(content.getCatalogId()),
|
||||
content.getOperator());
|
||||
|
||||
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
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.StringUtils;
|
||||
import com.chestnut.contentcore.domain.CmsContentOpLog;
|
||||
import com.chestnut.contentcore.service.IContentOpLogService;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 内容操作日志管理
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
*/
|
||||
@Priv(type = AdminUserType.TYPE)
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/cms/content/log")
|
||||
public class ContentOpLogController extends BaseRestController {
|
||||
|
||||
private final IContentOpLogService contentOpLogService;
|
||||
|
||||
@GetMapping
|
||||
public R<?> getContentOpLogPageList(@RequestParam Long contentId,
|
||||
@RequestParam(required = false) String type,
|
||||
@RequestParam(required = false) String operator) {
|
||||
PageRequest pr = this.getPageRequest();
|
||||
LambdaQueryWrapper<CmsContentOpLog> q = new LambdaQueryWrapper<CmsContentOpLog>()
|
||||
.eq(CmsContentOpLog::getContentId, contentId)
|
||||
.eq(StringUtils.isNotEmpty(type), CmsContentOpLog::getType, type)
|
||||
.eq(StringUtils.isNotEmpty(operator), CmsContentOpLog::getOperator, operator)
|
||||
.orderByDesc(CmsContentOpLog::getLogId);
|
||||
Page<CmsContentOpLog> pageResult = contentOpLogService.page(
|
||||
new Page<>(pr.getPageNumber(), pr.getPageSize(), true), q
|
||||
);
|
||||
return this.bindDataTable(pageResult);
|
||||
}
|
||||
}
|
||||
@ -25,6 +25,7 @@ import com.chestnut.common.utils.Assert;
|
||||
import com.chestnut.common.utils.ServletUtils;
|
||||
import com.chestnut.contentcore.core.IInternalDataType;
|
||||
import com.chestnut.contentcore.domain.CmsSite;
|
||||
import com.chestnut.contentcore.domain.vo.ContentPathRuleVO;
|
||||
import com.chestnut.contentcore.domain.vo.DynamicPageTypeVO;
|
||||
import com.chestnut.contentcore.exception.ContentCoreErrorCode;
|
||||
import com.chestnut.contentcore.service.ISiteService;
|
||||
@ -126,7 +127,6 @@ public class CoreController extends BaseRestController {
|
||||
@RequestParam(value = "pi", required = false, defaultValue = "1") Integer pageIndex,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
try {
|
||||
// TODO 缓存
|
||||
long s = System.currentTimeMillis();
|
||||
CmsSite site = this.siteService.getSite(siteId);
|
||||
// 模板ID = 通道:站点目录:模板文件名
|
||||
@ -164,9 +164,25 @@ public class CoreController extends BaseRestController {
|
||||
public R<?> getDynamicPageTypes() {
|
||||
List<DynamicPageTypeVO> list = ContentCoreUtils.getDynamicPageTypes().stream()
|
||||
.map(DynamicPageTypeVO::newInstance).toList();
|
||||
list.forEach( vo ->
|
||||
vo.setName(I18nUtils.get(vo.getName()))
|
||||
);
|
||||
list.forEach( vo -> {
|
||||
vo.setName(I18nUtils.get(vo.getName()));
|
||||
vo.setDesc(I18nUtils.get(vo.getDesc()));
|
||||
vo.getRequestArgs().forEach(requestArg -> {
|
||||
requestArg.setName(I18nUtils.get(requestArg.getName()));
|
||||
requestArg.setDesc(I18nUtils.get(requestArg.getDesc()));
|
||||
});
|
||||
});
|
||||
return R.ok(list);
|
||||
}
|
||||
|
||||
@Priv(type = AdminUserType.TYPE)
|
||||
@GetMapping("/cms/contentPathRules")
|
||||
public R<?> getContentPathRules() {
|
||||
List<ContentPathRuleVO> list = ContentCoreUtils.getContentPathRules().stream()
|
||||
.map(ContentPathRuleVO::newInstance).toList();
|
||||
list.forEach( vo -> {
|
||||
vo.setName(I18nUtils.get(vo.getName()));
|
||||
});
|
||||
return R.ok(list);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaMode;
|
||||
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.contentcore.domain.dto.ImageCropDTO;
|
||||
import com.chestnut.contentcore.domain.dto.ImageRotateDTO;
|
||||
import com.chestnut.contentcore.perms.ContentCorePriv;
|
||||
import com.chestnut.contentcore.service.IImageProcessService;
|
||||
import com.chestnut.contentcore.util.CmsPrivUtils;
|
||||
import com.chestnut.system.security.AdminUserType;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
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.io.IOException;
|
||||
|
||||
/**
|
||||
* 图片资源处理控制器
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
*/
|
||||
@Priv(
|
||||
type = AdminUserType.TYPE,
|
||||
value = { ContentCorePriv.ResourceView, CmsPrivUtils.PRIV_SITE_VIEW_PLACEHOLDER},
|
||||
mode = SaMode.AND
|
||||
)
|
||||
@RestController
|
||||
@RequestMapping("/cms/process/image")
|
||||
@RequiredArgsConstructor
|
||||
public class ImageProcessController extends BaseRestController {
|
||||
|
||||
private final IImageProcessService imageProcessService;
|
||||
|
||||
@Log(title = "图片裁剪", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/crop")
|
||||
public R<?> cropImage(@RequestBody @Validated ImageCropDTO dto) throws IOException {
|
||||
this.imageProcessService.cropImage(dto);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@Log(title = "旋转缩放", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/rotate")
|
||||
public R<?> rotateImage(@RequestBody @Validated ImageRotateDTO dto) throws IOException {
|
||||
this.imageProcessService.rotateImage(dto);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@Log(title = "文字水印", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/image/textWatermark")
|
||||
public R<?> textWatermark(@RequestBody @Validated ImageCropDTO dto) throws IOException {
|
||||
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@Log(title = "图片水印", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/image/imageWatermark")
|
||||
public R<?> imageWatermark(@RequestBody @Validated ImageCropDTO dto) throws IOException {
|
||||
|
||||
return R.ok();
|
||||
}
|
||||
}
|
||||
@ -34,7 +34,6 @@ import com.chestnut.contentcore.core.IResourceType;
|
||||
import com.chestnut.contentcore.core.impl.InternalDataType_Resource;
|
||||
import com.chestnut.contentcore.domain.CmsResource;
|
||||
import com.chestnut.contentcore.domain.CmsSite;
|
||||
import com.chestnut.contentcore.domain.dto.ImageCropDTO;
|
||||
import com.chestnut.contentcore.domain.dto.ResourceUploadDTO;
|
||||
import com.chestnut.contentcore.exception.ContentCoreErrorCode;
|
||||
import com.chestnut.contentcore.fixed.config.ResourceUploadAcceptSize;
|
||||
@ -52,7 +51,6 @@ import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
@ -198,11 +196,4 @@ public class ResourceController extends BaseRestController {
|
||||
Assert.notNull(resource, () -> CommonErrorCode.DATA_NOT_FOUND_BY_ID.exception("resourceId", resourceId));
|
||||
this.resourceService.downloadResource(resource, response);
|
||||
}
|
||||
|
||||
@Log(title = "图片裁剪", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/image/cut")
|
||||
public R<?> cutImage(@RequestBody @Validated ImageCropDTO imageCutDTO) {
|
||||
// TODO
|
||||
return R.fail("TODO");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -21,6 +21,7 @@ import com.chestnut.common.async.AsyncTask;
|
||||
import com.chestnut.common.async.AsyncTaskManager;
|
||||
import com.chestnut.common.domain.R;
|
||||
import com.chestnut.common.exception.CommonErrorCode;
|
||||
import com.chestnut.common.extend.annotation.XssIgnore;
|
||||
import com.chestnut.common.log.annotation.Log;
|
||||
import com.chestnut.common.log.enums.BusinessType;
|
||||
import com.chestnut.common.security.anno.Priv;
|
||||
@ -264,6 +265,7 @@ public class SiteController extends BaseRestController {
|
||||
* @param siteId 站点ID
|
||||
* @param configs 扩展配置数据
|
||||
*/
|
||||
@XssIgnore
|
||||
@Priv(type = AdminUserType.TYPE, value = "Site:Edit:${#siteId}")
|
||||
@Log(title = "站点扩展", businessType = BusinessType.UPDATE, isSaveRequestData = false)
|
||||
@PostMapping("/extends/{siteId}")
|
||||
|
||||
@ -15,28 +15,27 @@
|
||||
*/
|
||||
package com.chestnut.contentcore.controller;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.chestnut.common.domain.R;
|
||||
import com.chestnut.common.i18n.I18nUtils;
|
||||
import com.chestnut.common.security.anno.Priv;
|
||||
import com.chestnut.common.security.web.BaseRestController;
|
||||
import com.chestnut.common.staticize.func.IFunction;
|
||||
import com.chestnut.common.staticize.tag.ITag;
|
||||
import com.chestnut.common.utils.StringUtils;
|
||||
import com.chestnut.contentcore.domain.vo.TemplateFuncVO;
|
||||
import com.chestnut.contentcore.domain.vo.TemplateTagVO;
|
||||
import com.chestnut.contentcore.perms.ContentCorePriv;
|
||||
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.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 静态化管理
|
||||
*
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
*/
|
||||
@ -56,11 +55,22 @@ public class StaticizeController extends BaseRestController {
|
||||
@GetMapping("/tags")
|
||||
public R<?> getTemplateTags() {
|
||||
List<TemplateTagVO> list = this.tags.stream().map(tag -> {
|
||||
TemplateTagVO vo = TemplateTagVO.builder().name(I18nUtils.get(tag.getName())).tagName(tag.getTagName())
|
||||
.description(I18nUtils.get(tag.getDescription())).tagAttrs(tag.getTagAttrs()).build();
|
||||
TemplateTagVO vo = TemplateTagVO.builder()
|
||||
.name(I18nUtils.get(tag.getName()))
|
||||
.tagName(tag.getTagName())
|
||||
.description(I18nUtils.get(tag.getDescription()))
|
||||
.tagAttrs(tag.getTagAttrs())
|
||||
.demoLink("https://www.1000mz.com/docs/template/tags/" + tag.getTagName())
|
||||
.build();
|
||||
vo.getTagAttrs().forEach(attr -> {
|
||||
attr.setName(I18nUtils.get(attr.getName()));
|
||||
attr.setUsage(I18nUtils.get(attr.getUsage()));
|
||||
attr.setDefaultValue(I18nUtils.get(attr.getDefaultValue()));
|
||||
if (StringUtils.isNotEmpty(attr.getOptions())) {
|
||||
attr.getOptions().forEach(option -> {
|
||||
option.setDesc(I18nUtils.get(option.getDesc()));
|
||||
});
|
||||
}
|
||||
});
|
||||
return vo;
|
||||
}).toList();
|
||||
@ -73,8 +83,12 @@ public class StaticizeController extends BaseRestController {
|
||||
@GetMapping("/functions")
|
||||
public R<?> getTemplateFunctions() {
|
||||
List<TemplateFuncVO> list = this.functions.stream().map(func -> {
|
||||
TemplateFuncVO vo = TemplateFuncVO.builder().funcName(func.getFuncName())
|
||||
.desc(I18nUtils.get(func.getDesc())).funcArgs(func.getFuncArgs()).build();
|
||||
TemplateFuncVO vo = TemplateFuncVO.builder()
|
||||
.funcName(func.getFuncName())
|
||||
.desc(I18nUtils.get(func.getDesc()))
|
||||
.funcArgs(func.getFuncArgs())
|
||||
.demoLink("https://www.1000mz.com/docs/template/functions/" + func.getFuncName())
|
||||
.build();
|
||||
vo.getFuncArgs().forEach(arg -> {
|
||||
arg.setName(I18nUtils.get(arg.getName()));
|
||||
arg.setDesc(I18nUtils.get(arg.getDesc()));
|
||||
|
||||
@ -39,7 +39,10 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
@ -128,15 +131,10 @@ public class ContentApiController extends BaseRestController {
|
||||
if (pageResult.getRecords().isEmpty()) {
|
||||
return R.ok(List.of());
|
||||
}
|
||||
Map<Long, CmsCatalog> loadedCatalogs = new HashMap<>();
|
||||
List<ContentApiVO> list = new ArrayList<>();
|
||||
pageResult.getRecords().forEach(c -> {
|
||||
ContentApiVO dto = ContentApiVO.newInstance(c);
|
||||
CmsCatalog catalog = loadedCatalogs.get(c.getCatalogId());
|
||||
if (catalog == null) {
|
||||
catalog = this.catalogService.getCatalog(c.getCatalogId());
|
||||
loadedCatalogs.put(catalog.getCatalogId(), catalog);
|
||||
}
|
||||
CmsCatalog catalog = this.catalogService.getCatalog(c.getCatalogId());
|
||||
dto.setCatalogName(catalog.getName());
|
||||
dto.setCatalogLink(catalogService.getCatalogLink(catalog, 1, publishPipeCode, preview));
|
||||
dto.setLink(this.contentService.getContentLink(c, 1, publishPipeCode, preview));
|
||||
|
||||
@ -24,7 +24,9 @@ import com.chestnut.contentcore.domain.CmsContent;
|
||||
import com.chestnut.contentcore.domain.CmsSite;
|
||||
import com.chestnut.contentcore.enums.ContentCopyType;
|
||||
import com.chestnut.contentcore.exception.ContentCoreErrorCode;
|
||||
import com.chestnut.contentcore.fixed.dict.ContentOpType;
|
||||
import com.chestnut.contentcore.fixed.dict.ContentStatus;
|
||||
import com.chestnut.contentcore.listener.event.*;
|
||||
import com.chestnut.contentcore.properties.PublishedContentEditProperty;
|
||||
import com.chestnut.contentcore.service.ICatalogService;
|
||||
import com.chestnut.contentcore.service.IContentService;
|
||||
@ -32,6 +34,7 @@ import com.chestnut.contentcore.service.IPublishService;
|
||||
import com.chestnut.contentcore.service.ISiteService;
|
||||
import com.chestnut.contentcore.util.CatalogUtils;
|
||||
import com.chestnut.contentcore.util.ContentCoreUtils;
|
||||
import com.chestnut.contentcore.util.ContentLogUtils;
|
||||
import com.chestnut.contentcore.util.InternalUrlUtils;
|
||||
import com.chestnut.system.fixed.dict.YesOrNo;
|
||||
import lombok.Setter;
|
||||
@ -141,6 +144,8 @@ public abstract class AbstractContent<T> implements IContent<T> {
|
||||
throw ContentCoreErrorCode.TITLE_REPLEAT.exception();
|
||||
}
|
||||
checkRedirectUrl();
|
||||
|
||||
SpringUtils.publishEvent(new BeforeContentSaveEvent(this, this, true));
|
||||
content.setSiteId(catalog.getSiteId());
|
||||
content.setCatalogAncestors(catalog.getAncestors());
|
||||
content.setTopCatalog(CatalogUtils.getTopCatalog(catalog));
|
||||
@ -150,13 +155,24 @@ public abstract class AbstractContent<T> implements IContent<T> {
|
||||
content.setStatus(ContentStatus.DRAFT);
|
||||
content.setSortFlag(SortUtils.getDefaultSortValue());
|
||||
content.setIsLock(YesOrNo.NO);
|
||||
if (StringUtils.isEmpty(content.getLinkFlag())) {
|
||||
content.setLinkFlag(YesOrNo.NO);
|
||||
}
|
||||
if (Objects.isNull(content.getCopyType())) {
|
||||
content.setCopyType(ContentCopyType.NONE);
|
||||
}
|
||||
content.createBy(this.getOperatorUName());
|
||||
|
||||
this.getContentService().dao().save(this.getContentEntity());
|
||||
this.add0();
|
||||
// 栏目内容数+1
|
||||
this.getCatalogService().changeContentCount(catalog.getCatalogId(), 1);
|
||||
ContentLogUtils.addLog(ContentOpType.ADD, this.getContentEntity(), this.getOperator());
|
||||
SpringUtils.publishEvent(new AfterContentSaveEvent(this, this, true));
|
||||
return this.getContentEntity().getContentId();
|
||||
}
|
||||
|
||||
protected abstract void add0();
|
||||
|
||||
void checkLock() {
|
||||
boolean lockContent = content.isLock() && StringUtils.isNotEmpty(content.getLockUser())
|
||||
&& !content.getLockUser().equals(this.getOperatorUName());
|
||||
@ -190,26 +206,39 @@ public abstract class AbstractContent<T> implements IContent<T> {
|
||||
}
|
||||
}
|
||||
checkRedirectUrl();
|
||||
SpringUtils.publishEvent(new BeforeContentSaveEvent(this, this, false));
|
||||
if (ContentStatus.isToPublishOrPublished(content.getStatus())) {
|
||||
content.setStatus(ContentStatus.EDITING);
|
||||
}
|
||||
content.updateBy(this.getOperatorUName());
|
||||
contentService.dao().updateById(this.getContentEntity());
|
||||
this.save0();
|
||||
ContentLogUtils.addLog(ContentOpType.UPDATE, this.getContentEntity(), this.getOperator());
|
||||
SpringUtils.publishEvent(new AfterContentSaveEvent(this, this, false));
|
||||
return this.getContentEntity().getContentId();
|
||||
}
|
||||
|
||||
protected abstract void save0();
|
||||
|
||||
@Override
|
||||
public void delete() {
|
||||
this.checkLock();
|
||||
// 删除到备份表
|
||||
this.getContentService().dao().deleteByIdAndBackup(this.getContentEntity(), getOperatorUName());
|
||||
this.delete0();
|
||||
// 直接删除站内映射内容
|
||||
this.getContentService().dao().remove(new LambdaQueryWrapper<CmsContent>()
|
||||
.eq(CmsContent::getCopyType, ContentCopyType.Mapping)
|
||||
.eq(CmsContent::getCopyId, this.getContentEntity().getContentId()));
|
||||
// 栏目内容数-1
|
||||
this.getCatalogService().changeContentCount(getCatalogId(), -1);
|
||||
ContentLogUtils.addLog(ContentOpType.DELETE, this.getContentEntity(), this.getOperator());
|
||||
|
||||
SpringUtils.publishEvent(new AfterContentDeleteEvent(this, this));
|
||||
}
|
||||
|
||||
protected abstract void delete0();
|
||||
|
||||
@Override
|
||||
public boolean publish() {
|
||||
checkLock();
|
||||
@ -227,6 +256,7 @@ public abstract class AbstractContent<T> implements IContent<T> {
|
||||
}
|
||||
if (update) {
|
||||
this.getContentService().dao().updateById(content);
|
||||
ContentLogUtils.addLog(ContentOpType.PUBLISH, this.getContentEntity(), this.getOperator());
|
||||
}
|
||||
// 静态化
|
||||
this.getPublishService().asyncPublishContent(this);
|
||||
@ -263,12 +293,16 @@ public abstract class AbstractContent<T> implements IContent<T> {
|
||||
newContent.setOfflineDate(null);
|
||||
}
|
||||
this.getContentService().dao().save(newContent);
|
||||
this.getParams().put("NewContentId", newContent.getContentId());
|
||||
copyTo0(newContent, copyType);
|
||||
// 栏目内容数+1
|
||||
this.getCatalogService().changeContentCount(toCatalog.getCatalogId(), 1);
|
||||
|
||||
SpringUtils.publishEvent(new AfterContentCopyEvent(this, this.getContentEntity(), newContent));
|
||||
return newContent;
|
||||
}
|
||||
|
||||
protected abstract void copyTo0(CmsContent newContent, Integer copyType);
|
||||
|
||||
@Override
|
||||
public void moveTo(CmsCatalog toCatalog) {
|
||||
checkLock();
|
||||
@ -308,24 +342,26 @@ public abstract class AbstractContent<T> implements IContent<T> {
|
||||
if (ContentStatus.isPublished(this.getContentEntity().getStatus())) {
|
||||
this.getPublishService().publishContent(List.of(content.getContentId()), getOperator());
|
||||
}
|
||||
ContentLogUtils.addLog(ContentOpType.TOP, this.getContentEntity(), this.getOperator());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelTop() {
|
||||
content.setTopFlag(0L);
|
||||
content.setTopDate(null);
|
||||
content.updateBy(this.getOperatorUName());
|
||||
if (content.getTopFlag() > 0L) {
|
||||
return;
|
||||
}
|
||||
this.getContentService().dao().updateById(content);
|
||||
// 重新发布内容
|
||||
if (ContentStatus.isPublished(this.getContentEntity().getStatus())) {
|
||||
this.getPublishService().publishContent(List.of(content.getContentId()), getOperator());
|
||||
}
|
||||
ContentLogUtils.addLog(ContentOpType.CANCEL_TOP, this.getContentEntity(), this.getOperator());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sort(Long targetContentId) {
|
||||
if (targetContentId.equals(this.getContentEntity().getContentId())) {
|
||||
return; // 排序目标是自己直接返回
|
||||
return;
|
||||
}
|
||||
checkLock();
|
||||
CmsContent next = this.getContentService().dao().getById(targetContentId);
|
||||
@ -346,33 +382,41 @@ public abstract class AbstractContent<T> implements IContent<T> {
|
||||
}
|
||||
this.getContentEntity().updateBy(this.getOperatorUName());
|
||||
this.getContentService().dao().updateById(content);
|
||||
ContentLogUtils.addLog(ContentOpType.SORT, this.getContentEntity(), this.getOperator());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offline() {
|
||||
String status = this.getContentEntity().getStatus();
|
||||
this.getContentEntity().setStatus(ContentStatus.OFFLINE);
|
||||
this.getContentEntity().updateBy(this.getOperatorUName());
|
||||
this.getContentService().dao().updateById(this.getContentEntity());
|
||||
|
||||
if (ContentStatus.isPublished(status)) {
|
||||
// 已发布内容删除静态页面
|
||||
this.getContentService().deleteStaticFiles(this.getContentEntity());
|
||||
// 重新发布内容所在栏目和父级栏目
|
||||
String[] catalogIds = this.getContentEntity().getCatalogAncestors()
|
||||
.split(CatalogUtils.ANCESTORS_SPLITER);
|
||||
for (String catalogId : catalogIds) {
|
||||
this.getPublishService().publishCatalog(this.getCatalogService().getCatalog(Long.valueOf(catalogId)),
|
||||
false, false, null, this.getOperator());
|
||||
}
|
||||
if (!ContentStatus.isOffline(status)) {
|
||||
this.getContentEntity().setStatus(ContentStatus.OFFLINE);
|
||||
this.getContentEntity().updateBy(this.getOperatorUName());
|
||||
this.getContentService().dao().updateById(this.getContentEntity());
|
||||
}
|
||||
if (ContentStatus.isPublished(status)) {
|
||||
// 已发布内容删除静态页面
|
||||
this.getContentService().deleteStaticFiles(this.getContentEntity());
|
||||
// 重新发布内容所在栏目和父级栏目
|
||||
String[] catalogIds = this.getContentEntity().getCatalogAncestors()
|
||||
.split(CatalogUtils.ANCESTORS_SPLITER);
|
||||
for (String catalogId : catalogIds) {
|
||||
this.getPublishService().publishCatalog(this.getCatalogService().getCatalog(Long.valueOf(catalogId)),
|
||||
false, false, null, this.getOperator());
|
||||
}
|
||||
}
|
||||
ContentLogUtils.addLog(ContentOpType.OFFLINE, this.getContentEntity(), this.getOperator());
|
||||
SpringUtils.publishEvent(new AfterContentOfflineEvent(this, this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void toPublish() {
|
||||
this.getContentEntity().setStatus(ContentStatus.TO_PUBLISHED);
|
||||
this.getContentEntity().updateBy(this.getOperatorUName());
|
||||
this.getContentService().dao().updateById(this.getContentEntity());
|
||||
if (!ContentStatus.isToPublish(this.getContentEntity().getStatus())) {
|
||||
this.getContentEntity().setStatus(ContentStatus.TO_PUBLISHED);
|
||||
this.getContentEntity().updateBy(this.getOperatorUName());
|
||||
this.getContentService().dao().updateById(this.getContentEntity());
|
||||
}
|
||||
ContentLogUtils.addLog(ContentOpType.TO_PUBLISH, this.getContentEntity(), this.getOperator());
|
||||
SpringUtils.publishEvent(new AfterContentToPublishEvent(this, this));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -105,7 +105,7 @@ public abstract class AbstractPageWidget implements IPageWidget {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publish() throws TemplateException, IOException {
|
||||
public void publish() {
|
||||
CmsPageWidget pageWidgetEntity = this.getPageWidgetEntity();
|
||||
pageWidgetEntity.setState(PageWidgetStatus.PUBLISHED);
|
||||
pageWidgetEntity.updateBy(this.getOperator().getUsername());
|
||||
|
||||
@ -18,9 +18,8 @@ package com.chestnut.contentcore.core;
|
||||
import com.chestnut.contentcore.domain.BCmsContent;
|
||||
import com.chestnut.contentcore.domain.CmsContent;
|
||||
import com.chestnut.contentcore.domain.vo.ContentVO;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* 内容类型
|
||||
@ -79,11 +78,11 @@ public interface IContentType extends Comparable<IContentType> {
|
||||
IContent<?> loadContent(CmsContent xContent);
|
||||
|
||||
/**
|
||||
* 从请求读取内容数据
|
||||
* 从输入流读取内容数据
|
||||
*
|
||||
* @param request
|
||||
* @param is 输入流
|
||||
*/
|
||||
IContent<?> readRequest(HttpServletRequest request) throws IOException;
|
||||
IContent<?> readFrom(InputStream is);
|
||||
|
||||
/**
|
||||
* 初始化内容编辑页面数据
|
||||
|
||||
@ -17,6 +17,8 @@ package com.chestnut.contentcore.core;
|
||||
|
||||
import com.chestnut.common.staticize.core.TemplateContext;
|
||||
import com.chestnut.common.utils.StringUtils;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -31,9 +33,9 @@ public interface IDynamicPageType {
|
||||
|
||||
String BEAN_PREFIX = "DynamicPageType_";
|
||||
|
||||
RequestArg REQUEST_ARG_SITE_ID = new RequestArg("sid", "站点ID", RequestArgType.Parameter, true, null);
|
||||
RequestArg REQUEST_ARG_PUBLISHPIPE_CODE = new RequestArg("pp", "发布通道编码", RequestArgType.Parameter, true, null);
|
||||
RequestArg REQUEST_ARG_PREVIEW = new RequestArg("preview", "是否预览模式", RequestArgType.Parameter, false, "false");
|
||||
RequestArg REQUEST_ARG_SITE_ID = new RequestArg("sid", "{DYNAMIC_PAGE_TYPE.ARG.sid}", RequestArgType.Parameter, true);
|
||||
RequestArg REQUEST_ARG_PUBLISHPIPE_CODE = new RequestArg("pp", "{DYNAMIC_PAGE_TYPE.ARG.pp}", RequestArgType.Parameter, true);
|
||||
RequestArg REQUEST_ARG_PREVIEW = new RequestArg("preview", "{DYNAMIC_PAGE_TYPE.ARG.preview}", RequestArgType.Parameter, false, "false");
|
||||
|
||||
/**
|
||||
* 类型
|
||||
@ -89,17 +91,27 @@ public interface IDynamicPageType {
|
||||
|
||||
}
|
||||
|
||||
record RequestArg(
|
||||
String name, // 参数名
|
||||
@Getter
|
||||
@Setter
|
||||
class RequestArg {
|
||||
private String name;
|
||||
private String desc;
|
||||
private RequestArgType type;
|
||||
private boolean mandatory;
|
||||
private String defValue;
|
||||
|
||||
String desc, // 参数说明
|
||||
public RequestArg(String name, String desc, RequestArgType type, boolean mandatory) {
|
||||
this(name, desc, type, mandatory, null);
|
||||
}
|
||||
|
||||
RequestArgType type, // 类型:parameter, path
|
||||
|
||||
boolean mandatory, // 是否必填
|
||||
|
||||
String defaultValue // 默认值
|
||||
){}
|
||||
public RequestArg(String name, String desc, RequestArgType type, boolean mandatory, String defValue) {
|
||||
this.name = name;
|
||||
this.desc = desc;
|
||||
this.type = type;
|
||||
this.mandatory = mandatory;
|
||||
this.defValue = defValue;
|
||||
}
|
||||
}
|
||||
|
||||
enum RequestArgType {
|
||||
Parameter, Path
|
||||
|
||||
@ -15,13 +15,9 @@
|
||||
*/
|
||||
package com.chestnut.contentcore.core;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.chestnut.common.security.domain.LoginUser;
|
||||
import com.chestnut.contentcore.domain.CmsPageWidget;
|
||||
|
||||
import freemarker.template.TemplateException;
|
||||
|
||||
/**
|
||||
* 页面部件
|
||||
*
|
||||
@ -59,5 +55,5 @@ public interface IPageWidget {
|
||||
|
||||
void delete();
|
||||
|
||||
void publish() throws TemplateException, IOException;
|
||||
void publish();
|
||||
}
|
||||
|
||||
@ -79,4 +79,8 @@ public interface IResourceType {
|
||||
resource.setFileSize((long) bytes.length);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
default void afterProcess(CmsResource resource) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,17 +15,16 @@
|
||||
*/
|
||||
package com.chestnut.contentcore.core;
|
||||
|
||||
import com.chestnut.common.utils.StringUtils;
|
||||
import com.chestnut.contentcore.exception.InternalUrlParseException;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.web.util.HtmlUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.springframework.web.util.HtmlUtils;
|
||||
|
||||
import com.chestnut.common.utils.StringUtils;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 内部数据自定义URL<br/>
|
||||
* 内部数据包括:内容、栏目、站点、资源等<br/>
|
||||
@ -107,6 +106,9 @@ public class InternalURL {
|
||||
url = HtmlUtils.htmlUnescape(url);
|
||||
String content = url.substring(IURLProtocol.length());
|
||||
int i = content.lastIndexOf("?");
|
||||
if (i < 0) {
|
||||
throw new InternalUrlParseException("Invalid iurl: missing parameters.");
|
||||
}
|
||||
// 默认iurl的路径部分就是内部数据类型,如果参数中含有type则使用参数type,路径部分作为path
|
||||
String type = content.substring(0, i);
|
||||
iurl.setType(type);
|
||||
|
||||
@ -112,7 +112,7 @@ public class SiteImportContext implements ISiteThemeContext {
|
||||
if (IdUtils.validate(id)) {
|
||||
internalURL.setId(id);
|
||||
if (InternalDataType_Resource.ID.equals(internalURL.getType())) {
|
||||
internalURL.setParams(Map.of("sid", site.getSiteId().toString()));
|
||||
internalURL.getParams().put("sid", site.getSiteId().toString());
|
||||
}
|
||||
return internalURL.toIUrl();
|
||||
}
|
||||
|
||||
@ -64,10 +64,12 @@ public class ContentCoreResourceStat implements IResourceStat {
|
||||
*/
|
||||
private Set<Long> contentLogo() {
|
||||
Set<Long> resourceIds = new HashSet<>();
|
||||
this.contentService.dao().lambdaQuery().select(List.of(CmsContent::getLogo)).list().forEach(content -> {
|
||||
InternalURL internalURL = InternalUrlUtils.parseInternalUrl(content.getLogo());
|
||||
if (Objects.nonNull(internalURL)) {
|
||||
resourceIds.add(internalURL.getId());
|
||||
this.contentService.dao().lambdaQuery().select(List.of(CmsContent::getImages)).list().forEach(content -> {
|
||||
if (Objects.nonNull(content.getImages())) {
|
||||
InternalURL internalURL = InternalUrlUtils.parseInternalUrl(content.getLogo());
|
||||
if (Objects.nonNull(internalURL)) {
|
||||
resourceIds.add(internalURL.getId());
|
||||
}
|
||||
}
|
||||
});
|
||||
return resourceIds;
|
||||
|
||||
@ -53,7 +53,7 @@ public class InternalDataType_Catalog implements IInternalDataType {
|
||||
public String getPageData(RequestData requestData) throws IOException, TemplateException {
|
||||
CmsCatalog catalog = catalogService.getCatalog(requestData.getDataId());
|
||||
boolean listFlag = YesOrNo.isYes(requestData.getParams().get("list"));
|
||||
return this.publishService.getCatalogPageData(catalog, requestData.getPageIndex(), listFlag, requestData.getPublishPipeCode(), requestData.isPreview());
|
||||
return this.publishService.getCatalogPageData(catalog, requestData, listFlag);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -55,7 +55,7 @@ public class InternalDataType_Content implements IInternalDataType {
|
||||
CmsContent content = contentService.dao().getById(requestData.getDataId());
|
||||
Assert.notNull(content, () -> CommonErrorCode.DATA_NOT_FOUND_BY_ID.exception("contentId", requestData.getDataId()));
|
||||
|
||||
return this.publishService.getContentPageData(content, requestData.getPageIndex(), requestData.getPublishPipeCode(), requestData.isPreview());
|
||||
return this.publishService.getContentPageData(content, requestData);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -15,19 +15,17 @@
|
||||
*/
|
||||
package com.chestnut.contentcore.core.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.chestnut.contentcore.core.IInternalDataType;
|
||||
import com.chestnut.contentcore.core.InternalURL;
|
||||
import com.chestnut.contentcore.domain.CmsSite;
|
||||
import com.chestnut.contentcore.service.IPublishService;
|
||||
import com.chestnut.contentcore.service.ISiteService;
|
||||
import com.chestnut.contentcore.util.SiteUtils;
|
||||
|
||||
import freemarker.template.TemplateException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 内部数据类型:站点
|
||||
@ -53,7 +51,7 @@ public class InternalDataType_Site implements IInternalDataType {
|
||||
@Override
|
||||
public String getPageData(RequestData requestData) throws IOException, TemplateException {
|
||||
CmsSite site = siteService.getSite(requestData.getDataId());
|
||||
return this.publishService.getSitePageData(site, requestData.getPublishPipeCode(), requestData.isPreview());
|
||||
return this.publishService.getSitePageData(site, requestData);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -15,38 +15,31 @@
|
||||
*/
|
||||
package com.chestnut.contentcore.core.impl;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import com.chestnut.common.utils.file.ImageUtils;
|
||||
import com.chestnut.contentcore.properties.ThumbnailHeightProperty;
|
||||
import com.chestnut.contentcore.properties.ThumbnailWidthProperty;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.coobird.thumbnailator.Thumbnailator;
|
||||
import net.coobird.thumbnailator.util.ThumbnailatorUtils;
|
||||
import org.apache.commons.compress.utils.FileNameUtils;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.chestnut.common.storage.IFileStorageType;
|
||||
import com.chestnut.common.utils.StringUtils;
|
||||
import com.chestnut.common.utils.image.ImageHelper;
|
||||
import com.chestnut.common.utils.image.ImageUtils;
|
||||
import com.chestnut.common.utils.image.WatermarkPosition;
|
||||
import com.chestnut.contentcore.core.IResourceType;
|
||||
import com.chestnut.contentcore.domain.CmsResource;
|
||||
import com.chestnut.contentcore.domain.CmsSite;
|
||||
import com.chestnut.contentcore.enums.WatermarkerPosition;
|
||||
import com.chestnut.contentcore.properties.ImageWatermarkArgsProperty;
|
||||
import com.chestnut.contentcore.properties.*;
|
||||
import com.chestnut.contentcore.properties.ImageWatermarkArgsProperty.ImageWatermarkArgs;
|
||||
import com.chestnut.contentcore.properties.ImageWatermarkProperty;
|
||||
import com.chestnut.contentcore.service.ISiteService;
|
||||
import com.chestnut.contentcore.util.FileStorageHelper;
|
||||
import com.chestnut.contentcore.util.SiteUtils;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.coobird.thumbnailator.Thumbnails;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.compress.utils.FileNameUtils;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.*;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 资源类型:图片
|
||||
@ -67,6 +60,8 @@ public class ResourceType_Image implements IResourceType {
|
||||
|
||||
private final ISiteService siteService;
|
||||
|
||||
private final Map<String, IFileStorageType> fileStorageTypeMap;
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return ID;
|
||||
@ -90,49 +85,71 @@ public class ResourceType_Image implements IResourceType {
|
||||
@Override
|
||||
public byte[] process(CmsResource resource, byte[] bytes) throws IOException {
|
||||
CmsSite site = siteService.getSite(resource.getSiteId());
|
||||
// 提取图片宽高属性
|
||||
try (ByteArrayInputStream is = new ByteArrayInputStream(bytes)) {
|
||||
// 提取图片宽高属性
|
||||
BufferedImage bi = ImageIO.read(is);
|
||||
resource.setWidth(bi.getWidth());
|
||||
resource.setHeight(bi.getHeight());
|
||||
// 默认缩略图处理
|
||||
int w = ThumbnailWidthProperty.getValue(site.getConfigProps());
|
||||
int h = ThumbnailHeightProperty.getValue(site.getConfigProps());
|
||||
if (w > 0 && h > 0) {
|
||||
String siteResourceRoot = SiteUtils.getSiteResourceRoot(site);
|
||||
Thumbnails.of(bi).size(w, h).toFile(siteResourceRoot + ImageUtils.getThumbnailFileName(resource.getPath(), w, h));
|
||||
}
|
||||
// 添加水印
|
||||
if (ImageWatermarkProperty.getValue(site.getConfigProps())
|
||||
&& !"webp".equalsIgnoreCase(resource.getSuffix())) {
|
||||
// TODO webp水印支持
|
||||
if (ImageWatermarkProperty.getValue(site.getConfigProps())) {
|
||||
ImageWatermarkArgs args = ImageWatermarkArgsProperty.getValue(site.getConfigProps());
|
||||
if (StringUtils.isNotEmpty(args.getImage())) {
|
||||
// 水印图片占比大小调整
|
||||
String siteResourceRoot = SiteUtils.getSiteResourceRoot(site);
|
||||
File file = new File(siteResourceRoot + args.getImage());
|
||||
if (file.exists()) {
|
||||
float waterremakImageWidth = bi.getWidth() * args.getRatio() * 0.01f;
|
||||
BufferedImage biWatermarkImage = ImageIO.read(file);
|
||||
biWatermarkImage = Thumbnails.of(biWatermarkImage)
|
||||
.scale(waterremakImageWidth / biWatermarkImage.getWidth()).asBufferedImage();
|
||||
try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
|
||||
// 添加水印
|
||||
Thumbnails.of(bi)
|
||||
.watermark(WatermarkerPosition.valueOf(args.getPosition()).position(),
|
||||
biWatermarkImage, args.getOpacity())
|
||||
.scale(1f).outputFormat(resource.getSuffix()).toOutputStream(os);
|
||||
String ext = FilenameUtils.getExtension(resource.getFileName());
|
||||
ImageHelper.of(bi).format(ext).watermark(
|
||||
biWatermarkImage,
|
||||
args.getRatio() * 0.01f,
|
||||
args.getOpacity(),
|
||||
WatermarkPosition.str2Position(args.getPosition())
|
||||
).to(os);
|
||||
bytes = os.toByteArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("图片处理失败:", e);
|
||||
} catch (IOException e) {
|
||||
log.error("Read image failed: " + resource.getPath(), e);
|
||||
resource.setWidth(0);
|
||||
resource.setHeight(0);
|
||||
}
|
||||
resource.setFileSize((long) bytes.length);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterProcess(CmsResource resource) {
|
||||
CmsSite site = siteService.getSite(resource.getSiteId());
|
||||
int w = ThumbnailWidthProperty.getValue(site.getConfigProps());
|
||||
int h = ThumbnailHeightProperty.getValue(site.getConfigProps());
|
||||
if (w > 0 && h > 0) {
|
||||
// 读取存储配置
|
||||
String fileStorageType = FileStorageTypeProperty.getValue(site.getConfigProps());
|
||||
IFileStorageType fst = fileStorageTypeMap.get(IFileStorageType.BEAN_NAME_PREIFX + fileStorageType);
|
||||
FileStorageHelper fileStorageHelper = FileStorageHelper.of(fst, site);
|
||||
// 生成默认缩略图
|
||||
String ext = FilenameUtils.getExtension(resource.getFileName());
|
||||
String thumbnailPath = ImageUtils.getThumbnailFileName(resource.getPath(), w, h);
|
||||
InputStream read = fileStorageHelper.read(resource.getPath());
|
||||
try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
|
||||
ImageHelper.of(read).format(ext).resize(w, h).to(bos);
|
||||
fileStorageHelper.write(thumbnailPath, bos.toByteArray());
|
||||
} catch (IOException e) {
|
||||
log.warn("Generate default thumbnail image failed: " + resource.getPath(), e);
|
||||
// 生成缩略图失败直接使用源图作为缩略图
|
||||
fileStorageHelper.write(thumbnailPath, read);
|
||||
} finally {
|
||||
try {
|
||||
if (Objects.nonNull(read)) {
|
||||
read.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.warn("Input stream close err!", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,260 +1,254 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
|
||||
import com.chestnut.common.db.domain.BaseEntity;
|
||||
import com.chestnut.contentcore.core.impl.PublishPipeProp_IndexTemplate;
|
||||
import com.chestnut.contentcore.core.impl.PublishPipeProp_ListTemplate;
|
||||
import com.chestnut.system.fixed.dict.EnableOrDisable;
|
||||
import com.chestnut.system.fixed.dict.YesOrNo;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 栏目表对象 [cms_catalog]
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName(value = CmsCatalog.TABLE_NAME, autoResultMap = true)
|
||||
public class CmsCatalog extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static final String TABLE_NAME = "cms_catalog";
|
||||
|
||||
/**
|
||||
* 栏目ID
|
||||
*/
|
||||
@TableId(value = "catalog_id", type = IdType.INPUT)
|
||||
private Long catalogId;
|
||||
|
||||
/**
|
||||
* 站点ID
|
||||
*/
|
||||
private Long siteId;
|
||||
|
||||
/**
|
||||
* 父级栏目ID
|
||||
*/
|
||||
private Long parentId;
|
||||
|
||||
/**
|
||||
* 祖级栏目ID列表
|
||||
*/
|
||||
private String ancestors;
|
||||
|
||||
/**
|
||||
* 栏目名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 父级栏目名称(非表字段)
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private String parentName;
|
||||
|
||||
/**
|
||||
* logo
|
||||
*/
|
||||
private String logo;
|
||||
|
||||
/**
|
||||
* logo预览地址(非表字段)
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private String logoSrc;
|
||||
|
||||
/**
|
||||
* 栏目别名
|
||||
*/
|
||||
private String alias;
|
||||
|
||||
/**
|
||||
* 栏目简介
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 所属部门编码
|
||||
*/
|
||||
private String deptCode;
|
||||
|
||||
/**
|
||||
* 栏目类型
|
||||
*/
|
||||
private String catalogType;
|
||||
|
||||
/**
|
||||
* 栏目目录
|
||||
*/
|
||||
private String path;
|
||||
|
||||
/**
|
||||
* 跳转地址,标题栏目跳转地址
|
||||
*/
|
||||
private String redirectUrl;
|
||||
|
||||
/**
|
||||
* 是否生成静态页面
|
||||
*/
|
||||
private String staticFlag;
|
||||
|
||||
/**
|
||||
* 栏目是否可见
|
||||
*/
|
||||
private String visibleFlag;
|
||||
|
||||
/**
|
||||
* 栏目是否在标签中忽略
|
||||
*/
|
||||
private String tagIgnore;
|
||||
|
||||
/**
|
||||
* 排序字段
|
||||
*/
|
||||
private Long sortFlag;
|
||||
|
||||
/**
|
||||
* 栏目首页命名
|
||||
*/
|
||||
private String indexFileName;
|
||||
|
||||
/**
|
||||
* 列表页命名规则
|
||||
*/
|
||||
private String listNameRule;
|
||||
|
||||
/**
|
||||
* 详情页命名规则
|
||||
*/
|
||||
private String detailNameRule;
|
||||
|
||||
/**
|
||||
* 栏目层级
|
||||
*/
|
||||
private Integer treeLevel;
|
||||
|
||||
/**
|
||||
* 子栏目数
|
||||
*/
|
||||
private Integer childCount;
|
||||
|
||||
/**
|
||||
* 内容数量
|
||||
*/
|
||||
private Integer contentCount;
|
||||
|
||||
/**
|
||||
* 状态
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 点击量
|
||||
*/
|
||||
private Integer hitCount;
|
||||
|
||||
/**
|
||||
* SEO关键词
|
||||
*/
|
||||
private String seoKeywords;
|
||||
|
||||
/**
|
||||
* SEO描述
|
||||
*/
|
||||
private String seoDescription;
|
||||
|
||||
/**
|
||||
* SEO标题
|
||||
*/
|
||||
private String seoTitle;
|
||||
|
||||
/**
|
||||
* 链接(非表字段)
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private String link;
|
||||
|
||||
/**
|
||||
* 列表页链接(无首页模板时与link一致)
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private String listLink;
|
||||
|
||||
/**
|
||||
* 发布通道配置
|
||||
*/
|
||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||
private Map<String, Map<String, Object>> publishPipeProps;
|
||||
|
||||
/**
|
||||
* 扩展配置
|
||||
*/
|
||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||
private Map<String, String> configProps;
|
||||
|
||||
public Map<String, String> getConfigProps() {
|
||||
if (this.configProps == null) {
|
||||
this.configProps = new HashMap<>();
|
||||
}
|
||||
return configProps;
|
||||
}
|
||||
|
||||
public Map<String, Object> getPublishPipeProps(String publishPipeCode) {
|
||||
if (this.publishPipeProps == null) {
|
||||
this.publishPipeProps = new HashMap<>();
|
||||
}
|
||||
Map<String, Object> map = this.publishPipeProps.get(publishPipeCode);
|
||||
if (map == null) {
|
||||
map = new HashMap<>();
|
||||
this.publishPipeProps.put(publishPipeCode, map);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
public String getIndexTemplate(String publishPipeCode) {
|
||||
return PublishPipeProp_IndexTemplate.getValue(publishPipeCode, this.publishPipeProps);
|
||||
}
|
||||
|
||||
public String getListTemplate(String publishPipeCode) {
|
||||
return PublishPipeProp_ListTemplate.getValue(publishPipeCode, this.publishPipeProps);
|
||||
}
|
||||
|
||||
public boolean isStaticize() {
|
||||
return YesOrNo.isYes(this.staticFlag);
|
||||
}
|
||||
|
||||
public boolean isVisible() {
|
||||
return YesOrNo.isYes(this.visibleFlag);
|
||||
}
|
||||
|
||||
public boolean isEnable() {
|
||||
return EnableOrDisable.isEnable(this.status);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
|
||||
import com.chestnut.common.db.domain.BaseEntity;
|
||||
import com.chestnut.contentcore.core.impl.PublishPipeProp_IndexTemplate;
|
||||
import com.chestnut.contentcore.core.impl.PublishPipeProp_ListTemplate;
|
||||
import com.chestnut.system.fixed.dict.EnableOrDisable;
|
||||
import com.chestnut.system.fixed.dict.YesOrNo;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 栏目表对象 [cms_catalog]
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName(value = CmsCatalog.TABLE_NAME, autoResultMap = true)
|
||||
public class CmsCatalog extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static final String TABLE_NAME = "cms_catalog";
|
||||
|
||||
/**
|
||||
* 栏目ID
|
||||
*/
|
||||
@TableId(value = "catalog_id", type = IdType.INPUT)
|
||||
private Long catalogId;
|
||||
|
||||
/**
|
||||
* 站点ID
|
||||
*/
|
||||
private Long siteId;
|
||||
|
||||
/**
|
||||
* 父级栏目ID
|
||||
*/
|
||||
private Long parentId;
|
||||
|
||||
/**
|
||||
* 祖级栏目ID列表
|
||||
*/
|
||||
private String ancestors;
|
||||
|
||||
/**
|
||||
* 栏目名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 父级栏目名称(非表字段)
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private String parentName;
|
||||
|
||||
/**
|
||||
* logo
|
||||
*/
|
||||
private String logo;
|
||||
|
||||
/**
|
||||
* logo预览地址(非表字段)
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private String logoSrc;
|
||||
|
||||
/**
|
||||
* 栏目别名
|
||||
*/
|
||||
private String alias;
|
||||
|
||||
/**
|
||||
* 栏目简介
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 所属部门编码
|
||||
*/
|
||||
private String deptCode;
|
||||
|
||||
/**
|
||||
* 栏目类型
|
||||
*/
|
||||
private String catalogType;
|
||||
|
||||
/**
|
||||
* 栏目目录
|
||||
*/
|
||||
private String path;
|
||||
|
||||
/**
|
||||
* 跳转地址,标题栏目跳转地址
|
||||
*/
|
||||
private String redirectUrl;
|
||||
|
||||
/**
|
||||
* 是否生成静态页面
|
||||
*/
|
||||
private String staticFlag;
|
||||
|
||||
/**
|
||||
* 栏目是否可见
|
||||
*/
|
||||
private String visibleFlag;
|
||||
|
||||
/**
|
||||
* 栏目是否在标签中忽略
|
||||
*/
|
||||
private String tagIgnore;
|
||||
|
||||
/**
|
||||
* 排序字段
|
||||
*/
|
||||
private Long sortFlag;
|
||||
|
||||
/**
|
||||
* 栏目首页命名
|
||||
*/
|
||||
private String indexFileName;
|
||||
|
||||
/**
|
||||
* 列表页命名规则
|
||||
*/
|
||||
private String listNameRule;
|
||||
|
||||
/**
|
||||
* 详情页命名规则
|
||||
*/
|
||||
private String detailNameRule;
|
||||
|
||||
/**
|
||||
* 栏目层级
|
||||
*/
|
||||
private Integer treeLevel;
|
||||
|
||||
/**
|
||||
* 子栏目数
|
||||
*/
|
||||
private Integer childCount;
|
||||
|
||||
/**
|
||||
* 内容数量
|
||||
*/
|
||||
private Integer contentCount;
|
||||
|
||||
/**
|
||||
* 状态
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 点击量
|
||||
*/
|
||||
private Integer hitCount;
|
||||
|
||||
/**
|
||||
* SEO关键词
|
||||
*/
|
||||
private String seoKeywords;
|
||||
|
||||
/**
|
||||
* SEO描述
|
||||
*/
|
||||
private String seoDescription;
|
||||
|
||||
/**
|
||||
* SEO标题
|
||||
*/
|
||||
private String seoTitle;
|
||||
|
||||
/**
|
||||
* 链接(非表字段)
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private String link;
|
||||
|
||||
/**
|
||||
* 列表页链接(无首页模板时与link一致)
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private String listLink;
|
||||
|
||||
/**
|
||||
* 发布通道配置
|
||||
*/
|
||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||
private Map<String, Map<String, Object>> publishPipeProps;
|
||||
|
||||
/**
|
||||
* 扩展配置
|
||||
*/
|
||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||
private Map<String, String> configProps;
|
||||
|
||||
public Map<String, String> getConfigProps() {
|
||||
if (this.configProps == null) {
|
||||
this.configProps = new HashMap<>();
|
||||
}
|
||||
return configProps;
|
||||
}
|
||||
|
||||
public Map<String, Object> getPublishPipeProps(String publishPipeCode) {
|
||||
if (this.publishPipeProps == null) {
|
||||
this.publishPipeProps = new HashMap<>();
|
||||
}
|
||||
return this.publishPipeProps.computeIfAbsent(publishPipeCode, k -> new HashMap<>());
|
||||
}
|
||||
|
||||
public String getIndexTemplate(String publishPipeCode) {
|
||||
return PublishPipeProp_IndexTemplate.getValue(publishPipeCode, this.publishPipeProps);
|
||||
}
|
||||
|
||||
public String getListTemplate(String publishPipeCode) {
|
||||
return PublishPipeProp_ListTemplate.getValue(publishPipeCode, this.publishPipeProps);
|
||||
}
|
||||
|
||||
public boolean isStaticize() {
|
||||
return YesOrNo.isYes(this.staticFlag);
|
||||
}
|
||||
|
||||
public boolean isVisible() {
|
||||
return YesOrNo.isYes(this.visibleFlag);
|
||||
}
|
||||
|
||||
public boolean isEnable() {
|
||||
return EnableOrDisable.isEnable(this.status);
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,6 +30,7 @@ import org.springframework.beans.BeanUtils;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@ -119,10 +120,17 @@ public class CmsContent extends BaseEntity implements IBackupable<BCmsContent> {
|
||||
private String titleStyle;
|
||||
|
||||
/**
|
||||
* logo
|
||||
* 封面图
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private String logo;
|
||||
|
||||
/**
|
||||
* 新封面图字段
|
||||
*/
|
||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||
private List<String> images;
|
||||
|
||||
/**
|
||||
* 来源
|
||||
*/
|
||||
|
||||
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.chestnut.common.annotation.XComment;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 内容操作记录 [cms_content_op_log]
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName(CmsContentOpLog.TABLE_NAME)
|
||||
public class CmsContentOpLog implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static final String TABLE_NAME = "cms_content_op_log";
|
||||
|
||||
@TableId(value = "log_id", type = IdType.INPUT)
|
||||
@XComment("ID")
|
||||
private Long logId;
|
||||
|
||||
@XComment("所属站点ID")
|
||||
private Long siteId;
|
||||
|
||||
@XComment("所属内容ID")
|
||||
private Long contentId;
|
||||
|
||||
@XComment("操作类型")
|
||||
private String type;
|
||||
|
||||
@XComment("操作明细")
|
||||
private String details;
|
||||
|
||||
@XComment("操作人类型")
|
||||
private String operatorType;
|
||||
|
||||
@XComment("操作人用户名")
|
||||
private String operator;
|
||||
|
||||
@XComment("日志时间")
|
||||
private LocalDateTime logTime;
|
||||
}
|
||||
@ -140,12 +140,7 @@ public class CmsSite extends BaseEntity {
|
||||
if (this.publishPipeProps == null) {
|
||||
this.publishPipeProps = new HashMap<>();
|
||||
}
|
||||
Map<String, Object> map = this.publishPipeProps.get(publishPipeCode);
|
||||
if (map == null) {
|
||||
map = new HashMap<>();
|
||||
this.publishPipeProps.put(publishPipeCode, map);
|
||||
}
|
||||
return map;
|
||||
return this.publishPipeProps.computeIfAbsent(publishPipeCode, k -> new HashMap<>());
|
||||
}
|
||||
|
||||
public String getIndexTemplate(String publishPipeCode) {
|
||||
@ -158,9 +153,7 @@ public class CmsSite extends BaseEntity {
|
||||
|
||||
public String getUrl(String publishPipeCode) {
|
||||
String ppUrl = PublishPipeProp_SiteUrl.getValue(publishPipeCode, this.publishPipeProps);
|
||||
if (ppUrl != null && !ppUrl.endsWith("/")) {
|
||||
ppUrl += "/";
|
||||
}
|
||||
ppUrl = StringUtils.appendIfMissing(ppUrl, "/");
|
||||
return Objects.requireNonNullElse(ppUrl, StringUtils.EMPTY);
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,8 +18,8 @@ package com.chestnut.contentcore.domain;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.chestnut.common.annotation.XComment;
|
||||
import com.chestnut.common.db.domain.BaseEntity;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import lombok.Getter;
|
||||
@ -40,31 +40,21 @@ public class CmsSiteProperty extends BaseEntity {
|
||||
|
||||
public static final String TABLE_NAME = "cms_site_property";
|
||||
|
||||
/**
|
||||
* 属性ID-主键
|
||||
*/
|
||||
@TableId(value = "property_id", type = IdType.INPUT)
|
||||
@XComment("ID")
|
||||
private Long propertyId;
|
||||
|
||||
/**
|
||||
* 所属站点ID
|
||||
*/
|
||||
@XComment("所属站点ID")
|
||||
private Long siteId;
|
||||
|
||||
/**
|
||||
* 属性名称
|
||||
*/
|
||||
@XComment("属性名称")
|
||||
@NotBlank
|
||||
private String propName;
|
||||
|
||||
/**
|
||||
* 属性代码
|
||||
*/
|
||||
@Pattern(regexp = "[A-Za-z0-9_]+")
|
||||
@XComment("属性编码")
|
||||
@Pattern(regexp = "[A-Za-z0-9_]+", message = "{VALIDATOR.CMS.SITE_PROPERTY.REGEXP_ERR}")
|
||||
private String propCode;
|
||||
|
||||
/**
|
||||
* 属性值
|
||||
*/
|
||||
@XComment("属性值")
|
||||
private String propValue;
|
||||
}
|
||||
|
||||
@ -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.contentcore.domain;
|
||||
|
||||
import com.chestnut.common.utils.StringUtils;
|
||||
import com.chestnut.contentcore.fixed.dict.ContentAttribute;
|
||||
import com.chestnut.contentcore.util.InternalUrlUtils;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface InitByContent {
|
||||
|
||||
void setAttributes(String[] attributes);
|
||||
|
||||
void setLogo(String logo);
|
||||
|
||||
void setLogoSrc(String logoSrc);
|
||||
|
||||
void setImages(List<String> images);
|
||||
|
||||
void setImagesSrc(List<String> imagesSrc);
|
||||
|
||||
default void initByContent(CmsContent content, boolean preview) {
|
||||
BeanUtils.copyProperties(content, this);
|
||||
this.setAttributes(ContentAttribute.convertStr(content.getAttributes()));
|
||||
if (StringUtils.isNotEmpty(content.getImages())) {
|
||||
this.setLogo(content.getImages().get(0));
|
||||
if (preview) {
|
||||
this.setImagesSrc(content.getImages().stream().map(InternalUrlUtils::getActualPreviewUrl).toList());
|
||||
this.setLogoSrc(InternalUrlUtils.getActualPreviewUrl(content.getLogo()));
|
||||
}
|
||||
} else {
|
||||
this.setImages(List.of());
|
||||
this.setImagesSrc(List.of());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -21,7 +21,6 @@ import com.chestnut.system.validator.Dict;
|
||||
import com.chestnut.system.validator.LongId;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@ -92,6 +91,11 @@ public class CatalogUpdateDTO extends BaseDTO {
|
||||
*/
|
||||
private String redirectUrl;
|
||||
|
||||
/*
|
||||
* 内容路径规则
|
||||
*/
|
||||
private String detailNameRule;
|
||||
|
||||
/*
|
||||
* SEO关键词
|
||||
*/
|
||||
|
||||
@ -13,25 +13,22 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.chestnut.cms.stat.baidu.vo;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
package com.chestnut.contentcore.domain.dto;
|
||||
|
||||
import com.chestnut.common.security.domain.BaseDTO;
|
||||
import com.chestnut.system.validator.LongId;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class LineChartVO {
|
||||
public class ClearCatalogDTO extends BaseDTO {
|
||||
|
||||
/**
|
||||
* x轴
|
||||
* 栏目ID
|
||||
*/
|
||||
private List<String> xAxisDatas;
|
||||
|
||||
/**
|
||||
* y轴数据
|
||||
*/
|
||||
private Map<String, List<Object>> datas;
|
||||
@NotNull
|
||||
@LongId
|
||||
public Long catalogId;
|
||||
}
|
||||
@ -15,11 +15,15 @@
|
||||
*/
|
||||
package com.chestnut.contentcore.domain.dto;
|
||||
|
||||
import com.chestnut.common.utils.StringUtils;
|
||||
import com.chestnut.common.exception.CommonErrorCode;
|
||||
import com.chestnut.common.utils.Assert;
|
||||
import com.chestnut.contentcore.domain.CmsCatalog;
|
||||
import com.chestnut.contentcore.domain.CmsContent;
|
||||
import com.chestnut.contentcore.enums.ContentOpType;
|
||||
import com.chestnut.contentcore.domain.InitByContent;
|
||||
import com.chestnut.contentcore.fixed.dict.ContentAttribute;
|
||||
import com.chestnut.contentcore.util.InternalUrlUtils;
|
||||
import com.chestnut.contentcore.fixed.dict.ContentOpType;
|
||||
import com.chestnut.contentcore.service.ICatalogService;
|
||||
import com.chestnut.contentcore.service.IContentService;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
@ -31,12 +35,12 @@ import java.util.Map;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class ContentDTO {
|
||||
public class ContentDTO implements InitByContent {
|
||||
|
||||
/**
|
||||
* 操作类型
|
||||
*/
|
||||
private ContentOpType opType;
|
||||
private String opType;
|
||||
|
||||
/**
|
||||
* 内容ID
|
||||
@ -74,14 +78,24 @@ public class ContentDTO {
|
||||
private String titleStyle;
|
||||
|
||||
/**
|
||||
* 引导图
|
||||
* 封面图
|
||||
*/
|
||||
private String logo;
|
||||
|
||||
/**
|
||||
* 引导图预览路径
|
||||
* 封面图预览路径
|
||||
*/
|
||||
private String logoSrc;
|
||||
|
||||
/**
|
||||
* 其他图片
|
||||
*/
|
||||
private List<String> images = List.of();
|
||||
|
||||
/**
|
||||
* 其他图片预览路径
|
||||
*/
|
||||
private List<String> imagesSrc = List.of();
|
||||
|
||||
/**
|
||||
* 发布链接
|
||||
@ -257,14 +271,33 @@ public class ContentDTO {
|
||||
* 备用字段4
|
||||
*/
|
||||
private String prop4;
|
||||
|
||||
public CmsContent convertToContentEntity(ICatalogService catalogService, IContentService contentService) {
|
||||
CmsContent contentEntity;
|
||||
if (ContentOpType.UPDATE.equals(this.getOpType())) {
|
||||
contentEntity = contentService.dao().getById(this.getContentId());
|
||||
Assert.notNull(contentEntity,
|
||||
() -> CommonErrorCode.DATA_NOT_FOUND_BY_ID.exception("contentId", this.getContentId()));
|
||||
} else {
|
||||
contentEntity = new CmsContent();
|
||||
}
|
||||
BeanUtils.copyProperties(this, contentEntity);
|
||||
// 所属站点
|
||||
CmsCatalog catalog = catalogService.getCatalog(this.getCatalogId());
|
||||
contentEntity.setSiteId(catalog.getSiteId());
|
||||
contentEntity.setAttributes(ContentAttribute.convertInt(this.getAttributes()));
|
||||
// 发布通道配置
|
||||
Map<String, Map<String, Object>> publishPipProps = new HashMap<>();
|
||||
this.getPublishPipeProps().forEach(prop -> {
|
||||
publishPipProps.put(prop.getPipeCode(), prop.getProps());
|
||||
});
|
||||
contentEntity.setPublishPipeProps(publishPipProps);
|
||||
return contentEntity;
|
||||
}
|
||||
|
||||
public static ContentDTO newInstance(CmsContent cmsContent) {
|
||||
ContentDTO dto = new ContentDTO();
|
||||
BeanUtils.copyProperties(cmsContent, dto);
|
||||
dto.setAttributes(ContentAttribute.convertStr(cmsContent.getAttributes()));
|
||||
if (StringUtils.isNotEmpty(dto.getLogo())) {
|
||||
dto.setLogoSrc(InternalUrlUtils.getActualPreviewUrl(dto.getLogo()));
|
||||
}
|
||||
dto.initByContent(cmsContent, false);
|
||||
return dto;
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,5 +21,14 @@ import lombok.Setter;
|
||||
@Getter
|
||||
@Setter
|
||||
public class ImageCropDTO {
|
||||
|
||||
|
||||
private Long resourceId;
|
||||
|
||||
private Integer x;
|
||||
|
||||
private Integer y;
|
||||
|
||||
private Integer width;
|
||||
|
||||
private Integer height;
|
||||
}
|
||||
|
||||
@ -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.contentcore.domain.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class ImageRotateDTO {
|
||||
|
||||
private Long resourceId;
|
||||
|
||||
/**
|
||||
* 缩略图宽度
|
||||
*/
|
||||
private Integer width;
|
||||
|
||||
/**
|
||||
* 缩略图高度
|
||||
*/
|
||||
private Integer height;
|
||||
|
||||
/**
|
||||
* 旋转角度
|
||||
*/
|
||||
private Integer rotate;
|
||||
|
||||
/**
|
||||
* 水平翻转
|
||||
*/
|
||||
private Boolean flipX;
|
||||
|
||||
/**
|
||||
* 垂直翻转
|
||||
*/
|
||||
private Boolean flipY;
|
||||
}
|
||||
@ -13,42 +13,31 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.chestnut.cms.stat.baidu.vo;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
package com.chestnut.contentcore.domain.dto;
|
||||
|
||||
import com.chestnut.common.security.domain.BaseDTO;
|
||||
import com.chestnut.system.validator.LongId;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class BaiduTimeTrendVO extends LineChartVO {
|
||||
public class MergeCatalogDTO extends BaseDTO {
|
||||
|
||||
private Integer offset;
|
||||
/**
|
||||
* 栏目ID
|
||||
*/
|
||||
@NotNull
|
||||
@LongId
|
||||
public Long catalogId;
|
||||
|
||||
/**
|
||||
* 时间范围
|
||||
* 被合并栏目IDs
|
||||
*/
|
||||
private String timeSpan;
|
||||
|
||||
/**
|
||||
* 指标字段
|
||||
*/
|
||||
private List<String> fields;
|
||||
|
||||
/**
|
||||
* 总数
|
||||
*/
|
||||
private Integer total;
|
||||
|
||||
/**
|
||||
* 指标合计
|
||||
*/
|
||||
private Map<String, Object> sum;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private Map<String, Object> pageSum;
|
||||
@NotEmpty
|
||||
public List<Long> mergeCatalogIds;
|
||||
}
|
||||
@ -16,15 +16,15 @@
|
||||
package com.chestnut.contentcore.domain.vo;
|
||||
|
||||
import com.chestnut.contentcore.domain.CmsContent;
|
||||
import com.chestnut.contentcore.fixed.dict.ContentAttribute;
|
||||
import com.chestnut.contentcore.domain.InitByContent;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class ContentApiVO {
|
||||
public class ContentApiVO implements InitByContent {
|
||||
|
||||
/**
|
||||
* 内容ID
|
||||
@ -72,14 +72,24 @@ public class ContentApiVO {
|
||||
private String titleStyle;
|
||||
|
||||
/**
|
||||
* 引导图
|
||||
* 封面图
|
||||
*/
|
||||
private String logo;
|
||||
|
||||
/**
|
||||
* 引导图预览路径
|
||||
* 封面图预览路径
|
||||
*/
|
||||
private String logoSrc;
|
||||
|
||||
/**
|
||||
* 其他图片
|
||||
*/
|
||||
private List<String> images = List.of();
|
||||
|
||||
/**
|
||||
* 其他图片预览路径
|
||||
*/
|
||||
private List<String> imagesSrc = List.of();
|
||||
|
||||
/**
|
||||
* 发布链接
|
||||
@ -161,35 +171,9 @@ public class ContentApiVO {
|
||||
*/
|
||||
private Long viewCount;
|
||||
|
||||
protected void copyProperties(CmsContent content) {
|
||||
this.setAuthor(content.getAuthor());
|
||||
this.setCatalogId(content.getCatalogId());
|
||||
this.setContentId(content.getContentId());
|
||||
this.setContentType(content.getContentType());
|
||||
this.setEditor(content.getEditor());
|
||||
this.setKeywords(content.getKeywords());
|
||||
this.setLogo(content.getLogo());
|
||||
this.setOriginal(content.getOriginal());
|
||||
this.setPublishDate(content.getPublishDate().toInstant(ZoneOffset.UTC).toEpochMilli());
|
||||
this.setShortTitle(content.getShortTitle());
|
||||
this.setSubTitle(content.getSubTitle());
|
||||
this.setTitle(content.getTitle());
|
||||
this.setSource(content.getSource());
|
||||
this.setSourceUrl(content.getSourceUrl());
|
||||
this.setSummary(content.getSummary());
|
||||
this.setTags(content.getTags());
|
||||
this.setTitleStyle(content.getTitleStyle());
|
||||
this.setTopFlag(content.getTopFlag());
|
||||
this.setAttributes(ContentAttribute.convertStr(content.getAttributes()));
|
||||
this.setViewCount(content.getViewCount());
|
||||
this.setLikeCount(content.getLikeCount());
|
||||
this.setCommentCount(content.getCommentCount());
|
||||
this.setFavoriteCount(content.getFavoriteCount());
|
||||
}
|
||||
|
||||
public static ContentApiVO newInstance(CmsContent content) {
|
||||
ContentApiVO vo = new ContentApiVO();
|
||||
vo.copyProperties(content);
|
||||
vo.initByContent(content, false);
|
||||
return vo;
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,31 +13,24 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.chestnut.common.redis;
|
||||
package com.chestnut.contentcore.domain.vo;
|
||||
|
||||
import com.chestnut.contentcore.publish.IContentPathRule;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 被监控的Redis缓存数据
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class MonitoredCache {
|
||||
public class ContentPathRuleVO {
|
||||
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 缓存名称
|
||||
*/
|
||||
private String cacheName = "";
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 缓存键名
|
||||
*/
|
||||
private String cacheKey = "";
|
||||
|
||||
public MonitoredCache(String cacheName, String cacheKey) {
|
||||
this.cacheName = cacheName;
|
||||
this.cacheKey = cacheKey;
|
||||
public static ContentPathRuleVO newInstance(IContentPathRule contentPathRule) {
|
||||
ContentPathRuleVO vo = new ContentPathRuleVO();
|
||||
vo.setId(contentPathRule.getId());
|
||||
vo.setName(contentPathRule.getName());
|
||||
return vo;
|
||||
}
|
||||
}
|
||||
@ -15,26 +15,20 @@
|
||||
*/
|
||||
package com.chestnut.contentcore.domain.vo;
|
||||
|
||||
import com.chestnut.contentcore.domain.InitByContent;
|
||||
import com.chestnut.contentcore.domain.dto.PublishPipeProp;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
|
||||
import com.chestnut.common.utils.StringUtils;
|
||||
import com.chestnut.contentcore.domain.CmsContent;
|
||||
import com.chestnut.contentcore.domain.dto.PublishPipeProp;
|
||||
import com.chestnut.contentcore.fixed.dict.ContentAttribute;
|
||||
import com.chestnut.contentcore.util.InternalUrlUtils;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class ContentVO {
|
||||
public class ContentVO implements InitByContent {
|
||||
|
||||
/**
|
||||
* 内容ID
|
||||
@ -82,14 +76,24 @@ public class ContentVO {
|
||||
private String showSubTitle;
|
||||
|
||||
/**
|
||||
* 引导图
|
||||
* 封面图
|
||||
*/
|
||||
private String logo;
|
||||
|
||||
/**
|
||||
* 引导图预览路径
|
||||
* 封面图预览路径
|
||||
*/
|
||||
private String logoSrc;
|
||||
|
||||
/**
|
||||
* 新多图封面字段
|
||||
*/
|
||||
private List<String> images = List.of();
|
||||
|
||||
/**
|
||||
* 新多图封面预览路径
|
||||
*/
|
||||
private List<String> imagesSrc = List.of();
|
||||
|
||||
/**
|
||||
* 发布链接
|
||||
@ -265,14 +269,4 @@ public class ContentVO {
|
||||
* 自定义参数
|
||||
*/
|
||||
private Map<String, Object> params;
|
||||
|
||||
public static ContentVO newInstance(CmsContent cmsContent) {
|
||||
ContentVO dto = new ContentVO();
|
||||
BeanUtils.copyProperties(cmsContent, dto);
|
||||
dto.setAttributes(ContentAttribute.convertStr(cmsContent.getAttributes()));
|
||||
if (StringUtils.isNotEmpty(dto.getLogo())) {
|
||||
dto.setLogoSrc(InternalUrlUtils.getActualPreviewUrl(dto.getLogo()));
|
||||
}
|
||||
return dto;
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,17 +15,20 @@
|
||||
*/
|
||||
package com.chestnut.contentcore.domain.vo;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
|
||||
import com.chestnut.contentcore.core.impl.InternalDataType_Content;
|
||||
import com.chestnut.contentcore.domain.CmsContent;
|
||||
import com.chestnut.contentcore.domain.InitByContent;
|
||||
import com.chestnut.contentcore.util.InternalUrlUtils;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class ListContentVO {
|
||||
public class ListContentVO implements InitByContent {
|
||||
|
||||
/*
|
||||
* 内容ID
|
||||
@ -72,6 +75,16 @@ public class ListContentVO {
|
||||
*/
|
||||
private String logoSrc;
|
||||
|
||||
/*
|
||||
* 引导图
|
||||
*/
|
||||
private List<String> images;
|
||||
|
||||
/*
|
||||
* 引导图预览路径
|
||||
*/
|
||||
private List<String> imagesSrc;
|
||||
|
||||
/*
|
||||
* 内部链接
|
||||
*/
|
||||
@ -166,4 +179,11 @@ public class ListContentVO {
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
|
||||
public static ListContentVO newInstance(CmsContent content) {
|
||||
ListContentVO vo = new ListContentVO();
|
||||
vo.initByContent(content, true);
|
||||
vo.setInternalUrl(InternalUrlUtils.getInternalUrl(InternalDataType_Content.ID, content.getContentId()));
|
||||
return vo;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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.common.annotation.XComment;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* TagBaseVO
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class TagBaseVO {
|
||||
|
||||
@XComment("创建者")
|
||||
private String createBy;
|
||||
|
||||
@XComment("创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@XComment("更新者")
|
||||
private String updateBy;
|
||||
|
||||
@XComment("更新时间")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
@XComment("备注")
|
||||
private String remark;
|
||||
}
|
||||
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* 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.common.annotation.XComment;
|
||||
import com.chestnut.common.utils.StringUtils;
|
||||
import com.chestnut.contentcore.domain.CmsCatalog;
|
||||
import com.chestnut.contentcore.util.InternalUrlUtils;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 栏目标签数据对象
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class TagCatalogVO extends TagBaseVO {
|
||||
|
||||
@XComment("栏目ID")
|
||||
private Long catalogId;
|
||||
|
||||
@XComment("站点ID")
|
||||
private Long siteId;
|
||||
|
||||
@XComment("父级栏目ID")
|
||||
private Long parentId;
|
||||
|
||||
@XComment("祖级栏目IDs")
|
||||
private String ancestors;
|
||||
|
||||
@XComment("栏目名称")
|
||||
private String name;
|
||||
|
||||
@XComment("栏目引导图")
|
||||
private String logo;
|
||||
|
||||
@XComment(value = "栏目引导图访问路径", deprecated = true, forRemoval = "1.6.0")
|
||||
private String logoSrc;
|
||||
|
||||
@XComment("栏目别名")
|
||||
private String alias;
|
||||
|
||||
@XComment("栏目简介")
|
||||
private String description;
|
||||
|
||||
@XComment("所属部门编码")
|
||||
private String deptCode;
|
||||
|
||||
@XComment("栏目类型")
|
||||
private String catalogType;
|
||||
|
||||
@XComment("栏目目录")
|
||||
private String path;
|
||||
|
||||
@XComment("标题栏目跳转地址")
|
||||
private String redirectUrl;
|
||||
|
||||
@XComment("排序值")
|
||||
private Long sortFlag;
|
||||
|
||||
@XComment("栏目层级")
|
||||
private Integer treeLevel;
|
||||
|
||||
@XComment("子栏目数")
|
||||
private Integer childCount;
|
||||
|
||||
@XComment("内容数量")
|
||||
private Integer contentCount;
|
||||
|
||||
@XComment("SEO关键词")
|
||||
private String seoKeywords;
|
||||
|
||||
@XComment("SEO描述")
|
||||
private String seoDescription;
|
||||
|
||||
@XComment("SEO标题")
|
||||
private String seoTitle;
|
||||
|
||||
@XComment("扩展配置")
|
||||
private Map<String, String> configProps;
|
||||
|
||||
@XComment("栏目链接")
|
||||
private String link;
|
||||
|
||||
@XComment("列表页链接(无首页模板时与link一致)")
|
||||
private String listLink;
|
||||
|
||||
public static TagCatalogVO newInstance(CmsCatalog catalog, String publishPipeCode, boolean preview) {
|
||||
TagCatalogVO vo = new TagCatalogVO();
|
||||
BeanUtils.copyProperties(catalog, vo);
|
||||
if (StringUtils.isNotEmpty(catalog.getLogo())) {
|
||||
// 兼容历史版本
|
||||
vo.setLogoSrc(InternalUrlUtils.getActualUrl(catalog.getLogo(), publishPipeCode, preview));
|
||||
}
|
||||
return vo;
|
||||
}
|
||||
|
||||
public Map<String, String> getConfigProps() {
|
||||
if (this.configProps == null) {
|
||||
this.configProps = new HashMap<>();
|
||||
}
|
||||
return configProps;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,180 @@
|
||||
/*
|
||||
* 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.common.annotation.XComment;
|
||||
import com.chestnut.common.utils.StringUtils;
|
||||
import com.chestnut.contentcore.domain.CmsContent;
|
||||
import com.chestnut.contentcore.fixed.dict.ContentAttribute;
|
||||
import com.chestnut.contentcore.util.InternalUrlUtils;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 内容标签数据对象
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class TagContentVO extends TagBaseVO {
|
||||
|
||||
@XComment("内容ID")
|
||||
private Long contentId;
|
||||
|
||||
@XComment("所属站点ID")
|
||||
private Long siteId;
|
||||
|
||||
@XComment("所属栏目ID")
|
||||
private Long catalogId;
|
||||
|
||||
@XComment("所属栏目祖级IDs")
|
||||
private String catalogAncestors;
|
||||
|
||||
@XComment("所属顶级栏目")
|
||||
private Long topCatalog;
|
||||
|
||||
@XComment("所属部门ID")
|
||||
private Long deptId;
|
||||
|
||||
@XComment("所属部门编码")
|
||||
private String deptCode;
|
||||
|
||||
@XComment("内容类型")
|
||||
private String contentType;
|
||||
|
||||
@XComment("标题")
|
||||
private String title;
|
||||
|
||||
@XComment("副标题")
|
||||
private String subTitle;
|
||||
|
||||
@XComment("短标题")
|
||||
private String shortTitle;
|
||||
|
||||
@XComment("标题样式")
|
||||
private String titleStyle;
|
||||
|
||||
@XComment(value = "封面图", deprecated = true, forRemoval = "1.6.0")
|
||||
private String logo;
|
||||
|
||||
@XComment(value = "封面图访问路径", deprecated = true, forRemoval = "1.6.0")
|
||||
private String logoSrc;
|
||||
|
||||
@XComment("封面图列表")
|
||||
private List<String> images;
|
||||
|
||||
@XComment("来源")
|
||||
private String source;
|
||||
|
||||
@XComment("来源URL")
|
||||
private String sourceUrl;
|
||||
|
||||
@XComment("是否原创")
|
||||
private String original;
|
||||
|
||||
@XComment("作者")
|
||||
private String author;
|
||||
|
||||
@XComment("编辑")
|
||||
private String editor;
|
||||
|
||||
@XComment("投稿用户ID")
|
||||
private Long contributorId;
|
||||
|
||||
@XComment("摘要")
|
||||
private String summary;
|
||||
|
||||
@XComment("内容属性标识列表")
|
||||
private String[] attributes;
|
||||
|
||||
@XComment("是否链接内容")
|
||||
private String linkFlag;
|
||||
|
||||
@XComment("跳转链接(linkFlag==Y)")
|
||||
private String redirectUrl;
|
||||
|
||||
@XComment("置顶标识")
|
||||
private Long topFlag;
|
||||
|
||||
@XComment("置顶结束时间")
|
||||
private LocalDateTime topDate;
|
||||
|
||||
@XComment("排序值")
|
||||
private Long sortFlag;
|
||||
|
||||
@XComment("关键词")
|
||||
private String[] keywords;
|
||||
|
||||
@XComment("TAGs")
|
||||
private String[] tags;
|
||||
|
||||
@XComment("发布时间")
|
||||
private LocalDateTime publishDate;
|
||||
|
||||
@XComment("SEO标题")
|
||||
private String seoTitle;
|
||||
|
||||
@XComment("SEO关键词")
|
||||
private String seoKeywords;
|
||||
|
||||
@XComment("SEO描述")
|
||||
private String seoDescription;
|
||||
|
||||
@XComment("点赞数(非实时)")
|
||||
private Long likeCount;
|
||||
|
||||
@XComment("评论数(非实时)")
|
||||
private Long commentCount;
|
||||
|
||||
@XComment("收藏数(非实时)")
|
||||
private Long favoriteCount;
|
||||
|
||||
@XComment("文章浏览数(非实时)")
|
||||
private Long viewCount;
|
||||
|
||||
@XComment("备用字段1")
|
||||
private String prop1;
|
||||
|
||||
@XComment("备用字段2")
|
||||
private String prop2;
|
||||
|
||||
@XComment("备用字段3")
|
||||
private String prop3;
|
||||
|
||||
@XComment("备用字段4")
|
||||
private String prop4;
|
||||
|
||||
@XComment("内容链接")
|
||||
private String link;
|
||||
|
||||
public static TagContentVO newInstance(CmsContent content, String publishPipeCode, boolean preview) {
|
||||
TagContentVO vo = new TagContentVO();
|
||||
BeanUtils.copyProperties(content, vo);
|
||||
vo.setAttributes(ContentAttribute.convertStr(content.getAttributes()));
|
||||
if (StringUtils.isNotEmpty(content.getImages())) {
|
||||
// 兼容历史版本
|
||||
vo.setLogo(content.getImages().get(0));
|
||||
vo.setLogoSrc(InternalUrlUtils.getActualUrl(content.getLogo(), publishPipeCode, preview));
|
||||
}
|
||||
return vo;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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.common.annotation.XComment;
|
||||
import com.chestnut.contentcore.domain.CmsPageWidget;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
|
||||
/**
|
||||
* 栏目标签数据对象
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class TagPageWidgetVO {
|
||||
|
||||
@XComment("页面部件ID")
|
||||
private Long pageWidgetId;
|
||||
|
||||
@XComment("所属站点ID")
|
||||
private Long siteId;
|
||||
|
||||
@XComment("所属栏目ID")
|
||||
private Long catalogId;
|
||||
|
||||
@XComment("所属栏目祖级IDs")
|
||||
private String catalogAncestors;
|
||||
|
||||
@XComment("类型")
|
||||
private String type;
|
||||
|
||||
@XComment("名称")
|
||||
private String name;
|
||||
|
||||
@XComment("编码")
|
||||
private String code;
|
||||
|
||||
@XComment("发布通道")
|
||||
private String publishPipeCode;
|
||||
|
||||
@XComment("页面部件扩展数据")
|
||||
private Object contentObj;
|
||||
|
||||
public static TagPageWidgetVO newInstance(CmsPageWidget pageWidget) {
|
||||
TagPageWidgetVO vo = new TagPageWidgetVO();
|
||||
BeanUtils.copyProperties(pageWidget, vo);
|
||||
return vo;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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.common.annotation.XComment;
|
||||
import com.chestnut.common.utils.StringUtils;
|
||||
import com.chestnut.contentcore.domain.CmsSite;
|
||||
import com.chestnut.contentcore.util.InternalUrlUtils;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 站点标签数据对象
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class TagSiteVO extends TagBaseVO {
|
||||
|
||||
@XComment("站点ID")
|
||||
private Long siteId;
|
||||
|
||||
@XComment("父级站点ID")
|
||||
private Long parentId;
|
||||
|
||||
@XComment("站点名称")
|
||||
private String name;
|
||||
|
||||
@XComment("站点描述")
|
||||
private String description;
|
||||
|
||||
@XComment("站点LOGO")
|
||||
private String logo;
|
||||
|
||||
@XComment(value = "站点LOGO访问地址", deprecated = true, forRemoval = "1.6.0")
|
||||
private String logoSrc;
|
||||
|
||||
@XComment("站点目录")
|
||||
private String path;
|
||||
|
||||
@XComment("站点资源访问域名")
|
||||
private String resourceUrl;
|
||||
|
||||
@XComment("所属部门编码")
|
||||
private String deptCode;
|
||||
|
||||
@XComment("排序值")
|
||||
private Long sortFlag;
|
||||
|
||||
@XComment("SEO关键词")
|
||||
private String seoKeywords;
|
||||
|
||||
@XComment("SEO描述")
|
||||
private String seoDescription;
|
||||
|
||||
@XComment("SEO标题")
|
||||
private String seoTitle;
|
||||
|
||||
@XComment("扩展属性配置")
|
||||
private Map<String, String> configProps;
|
||||
|
||||
@XComment("站点访问地址")
|
||||
private String link;
|
||||
|
||||
public static TagSiteVO newInstance(CmsSite site, String publishPipeCode, boolean preview) {
|
||||
TagSiteVO vo = new TagSiteVO();
|
||||
BeanUtils.copyProperties(site, vo);
|
||||
if (StringUtils.isNotEmpty(site.getLogo())) {
|
||||
// 兼容历史版本
|
||||
vo.setLogoSrc(InternalUrlUtils.getActualUrl(site.getLogo(), publishPipeCode, preview));
|
||||
}
|
||||
return vo;
|
||||
}
|
||||
|
||||
public Map<String, String> getConfigProps() {
|
||||
if (this.configProps == null) {
|
||||
this.configProps = new HashMap<>();
|
||||
}
|
||||
return configProps;
|
||||
}
|
||||
}
|
||||
@ -15,14 +15,13 @@
|
||||
*/
|
||||
package com.chestnut.contentcore.domain.vo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.chestnut.common.staticize.func.IFunction.FuncArg;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@ -35,4 +34,6 @@ public class TemplateFuncVO {
|
||||
private String desc;
|
||||
|
||||
private List<FuncArg> funcArgs;
|
||||
|
||||
private String demoLink;
|
||||
}
|
||||
|
||||
@ -15,14 +15,13 @@
|
||||
*/
|
||||
package com.chestnut.contentcore.domain.vo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.chestnut.common.staticize.tag.TagAttr;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@ -35,4 +34,6 @@ public class TemplateTagVO {
|
||||
private String description;
|
||||
|
||||
private List<TagAttr> tagAttrs;
|
||||
|
||||
private String demoLink;
|
||||
}
|
||||
|
||||
@ -20,9 +20,13 @@ import java.util.Objects;
|
||||
/**
|
||||
* 内容复制方式
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
*/
|
||||
public class ContentCopyType {
|
||||
|
||||
public static final int NONE = 0;
|
||||
|
||||
/**
|
||||
* 独立复制,完整拷贝内容所有信息,拷贝的内容变更与源内容无关,仅仅记录来源
|
||||
*/
|
||||
|
||||
@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022-2024 兮玥(190785909@qq.com)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.chestnut.contentcore.enums;
|
||||
|
||||
import net.coobird.thumbnailator.geometry.Position;
|
||||
import net.coobird.thumbnailator.geometry.Positions;
|
||||
|
||||
public enum WatermarkerPosition {
|
||||
|
||||
TOP_LEFT(Positions.TOP_LEFT), // 左上
|
||||
|
||||
TOP_CENTER(Positions.TOP_CENTER), // 上
|
||||
|
||||
TOP_RIGHT(Positions.TOP_RIGHT), // 右上
|
||||
|
||||
CENTER_LEFT(Positions.CENTER_LEFT), // 左
|
||||
|
||||
CENTER(Positions.CENTER), // 中
|
||||
|
||||
CENTER_RIGHT(Positions.CENTER_RIGHT), // 右
|
||||
|
||||
BOTTOM_LEFT(Positions.BOTTOM_LEFT), // 左下
|
||||
|
||||
BOTTOM_CENTER(Positions.BOTTOM_CENTER), // 下
|
||||
|
||||
BOTTOM_RIGHT(Positions.BOTTOM_RIGHT); // 右下
|
||||
|
||||
private Position position;
|
||||
|
||||
WatermarkerPosition(Position position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public Position position() {
|
||||
return position;
|
||||
}
|
||||
}
|
||||
@ -15,6 +15,12 @@
|
||||
*/
|
||||
package com.chestnut.contentcore.enums;
|
||||
|
||||
/**
|
||||
* 水印类型
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
*/
|
||||
public enum WatermarkerType {
|
||||
|
||||
/**
|
||||
@ -23,7 +29,7 @@ public enum WatermarkerType {
|
||||
NONE,
|
||||
|
||||
/**
|
||||
* 图片谁赢
|
||||
* 图片水印
|
||||
*/
|
||||
IMAGE,
|
||||
|
||||
|
||||
@ -69,6 +69,11 @@ public enum ContentCoreErrorCode implements ErrorCode {
|
||||
*/
|
||||
UNSUPPORTED_DYNAMIC_PAGE_TYPE,
|
||||
|
||||
/**
|
||||
* 不支持的内容详情页路径规则:{0}
|
||||
*/
|
||||
UNSUPPORTED_CONTENT_PATH_RULE,
|
||||
|
||||
/**
|
||||
* 请先删除子栏目
|
||||
*/
|
||||
@ -177,7 +182,27 @@ public enum ContentCoreErrorCode implements ErrorCode {
|
||||
/**
|
||||
* 上传文件超过限制
|
||||
*/
|
||||
RESOURCE_ACCEPT_SIZE_LIMIT;
|
||||
RESOURCE_ACCEPT_SIZE_LIMIT,
|
||||
|
||||
/**
|
||||
* 不能处理非图片资源
|
||||
*/
|
||||
ONLY_SUPPORT_IMAGE,
|
||||
|
||||
/**
|
||||
* 资源存储方式与站点配置不一致
|
||||
*/
|
||||
UNSUPPORTED_RESOURCE_STORAGE,
|
||||
|
||||
/**
|
||||
* 被合并栏目不能为空
|
||||
*/
|
||||
MERGE_CATALOG_IS_EMPTY,
|
||||
|
||||
/**
|
||||
* 不能合并包含子栏目的栏目
|
||||
*/
|
||||
MERGE_CATALOG_NOT_LEAF;
|
||||
|
||||
@Override
|
||||
public String value() {
|
||||
|
||||
@ -13,17 +13,21 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.chestnut.contentcore.exception;
|
||||
|
||||
/**
|
||||
* InternalUrlParseException
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
*/
|
||||
public class InternalUrlParseException extends RuntimeException {
|
||||
|
||||
public InternalUrlParseException(String message, Exception e) {
|
||||
super("Parse iurl failed: " + message, e);
|
||||
}
|
||||
}
|
||||
package com.chestnut.contentcore.exception;
|
||||
|
||||
/**
|
||||
* InternalUrlParseException
|
||||
*
|
||||
* @author 兮玥
|
||||
* @email 190785909@qq.com
|
||||
*/
|
||||
public class InternalUrlParseException extends RuntimeException {
|
||||
|
||||
public InternalUrlParseException(String message) {
|
||||
super("Parse iurl failed: " + message);
|
||||
}
|
||||
|
||||
public InternalUrlParseException(String message, Exception e) {
|
||||
super("Parse iurl failed: " + message, e);
|
||||
}
|
||||
}
|
||||
|
||||
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