Compare commits
47 Commits
@ -0,0 +1,45 @@
|
||||
### Java template
|
||||
# Compiled class file
|
||||
*.class
|
||||
|
||||
# Log file
|
||||
*.log
|
||||
|
||||
# BlueJ files
|
||||
*.ctxt
|
||||
|
||||
# Mobile Tools for Java (J2ME)
|
||||
.mtj.tmp/
|
||||
|
||||
# Package Files #
|
||||
*.jar
|
||||
*.war
|
||||
*.nar
|
||||
*.ear
|
||||
*.zip
|
||||
*.tar.gz
|
||||
*.rar
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
replay_pid*
|
||||
|
||||
### Maven template
|
||||
/.idea
|
||||
**/target/
|
||||
pom.xml.tag
|
||||
pom.xml.releaseBackup
|
||||
pom.xml.versionsBackup
|
||||
pom.xml.next
|
||||
release.properties
|
||||
dependency-reduced-pom.xml
|
||||
buildNumber.properties
|
||||
.mvn/timing.properties
|
||||
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
|
||||
.mvn/wrapper/maven-wrapper.jar
|
||||
|
||||
# Eclipse m2e generated files
|
||||
# Eclipse Core
|
||||
.project
|
||||
# JDT-specific (Eclipse Java Development Tools)
|
||||
.classpath
|
@ -1,8 +0,0 @@
|
||||
# 默认忽略的文件
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# 基于编辑器的 HTTP 客户端请求
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
@ -1,22 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<annotationProcessing>
|
||||
<profile default="true" name="Default" enabled="true" />
|
||||
<profile name="Maven default annotation processors profile" enabled="true">
|
||||
<sourceOutputDir name="target/generated-sources/annotations" />
|
||||
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
|
||||
<outputRelativeToContentRoot value="true" />
|
||||
<module name="common" />
|
||||
<module name="service" />
|
||||
</profile>
|
||||
</annotationProcessing>
|
||||
</component>
|
||||
<component name="JavacSettings">
|
||||
<option name="ADDITIONAL_OPTIONS_OVERRIDE">
|
||||
<module name="common" options="-parameters" />
|
||||
<module name="luojia_channel" options="" />
|
||||
<module name="service" options="-parameters" />
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||
<data-source source="LOCAL" name="luojia_channel@192.168.125.128" uuid="666814a4-5179-4ab7-96f4-c2a810ed102b">
|
||||
<driver-ref>mysql.8</driver-ref>
|
||||
<synchronize>true</synchronize>
|
||||
<imported>true</imported>
|
||||
<remarks>$PROJECT_DIR$/service/src/main/resources/application.yaml</remarks>
|
||||
<jdbc-driver>com.mysql.cj.jdbc.Driver</jdbc-driver>
|
||||
<jdbc-url>jdbc:mysql://192.168.125.128:3306/luojia_channel?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai</jdbc-url>
|
||||
<jdbc-additional-properties>
|
||||
<property name="com.intellij.clouds.kubernetes.db.host.port" />
|
||||
<property name="com.intellij.clouds.kubernetes.db.enabled" value="false" />
|
||||
<property name="com.intellij.clouds.kubernetes.db.resource.type" value="Deployment" />
|
||||
<property name="com.intellij.clouds.kubernetes.db.container.port" />
|
||||
</jdbc-additional-properties>
|
||||
<working-dir>$ProjectFileDir$</working-dir>
|
||||
</data-source>
|
||||
</component>
|
||||
</project>
|
@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding">
|
||||
<file url="file://$PROJECT_DIR$/common/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/service/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
|
||||
</component>
|
||||
</project>
|
@ -1,6 +0,0 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
</profile>
|
||||
</component>
|
@ -1,25 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RemoteRepositoriesConfiguration">
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Central Repository" />
|
||||
<option name="url" value="https://repo.maven.apache.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Maven Central repository" />
|
||||
<option name="url" value="https://repo1.maven.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="jboss.community" />
|
||||
<option name="name" value="JBoss Community repository" />
|
||||
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Central Repository" />
|
||||
<option name="url" value="https://maven.aliyun.com/repository/public" />
|
||||
</remote-repository>
|
||||
</component>
|
||||
</project>
|
@ -1,14 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="MavenProjectsManager">
|
||||
<option name="originalFiles">
|
||||
<list>
|
||||
<option value="$PROJECT_DIR$/pom.xml" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="17" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
@ -1,17 +0,0 @@
|
||||
|
||||
{
|
||||
"luatools_path": "~/go/bin",
|
||||
"dto_dir": "./ngx_conf/dto",
|
||||
"swagger.docs.path": "./docs",
|
||||
"swagger.excludes": "./client",
|
||||
"swagger.file.type": "json",
|
||||
"swagger.main.lua.path": "./main.lua",
|
||||
"swagger.name": "swagger",
|
||||
"swagger.search_dirs": "./ngx_conf,./config/cn/online",
|
||||
"validator_dir": "./ngx_conf/validator",
|
||||
"yapi.config.file": "docs/swagger-yapi.json",
|
||||
"yapi.config.mode": "mergin",
|
||||
"yapi.config.server": "https://api.yapi.net",
|
||||
"yapi.config.token": "xxxxxxxxx"
|
||||
}
|
||||
|
@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="SqlDialectMappings">
|
||||
<file url="file://$PROJECT_DIR$/service/src/main/resources/db/data.sql" dialect="GenericSQL" />
|
||||
<file url="file://$PROJECT_DIR$/service/src/main/resources/db/luojia_channel.sql" dialect="MySQL" />
|
||||
<file url="PROJECT" dialect="MySQL" />
|
||||
</component>
|
||||
</project>
|
@ -1,124 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Palette2">
|
||||
<group name="Swing">
|
||||
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
|
||||
</item>
|
||||
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.svg" removable="false" auto-create-binding="false" can-attach-label="true">
|
||||
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
|
||||
<initial-values>
|
||||
<property name="text" value="Button" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="RadioButton" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="CheckBox" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
|
||||
<initial-values>
|
||||
<property name="text" value="Label" />
|
||||
</initial-values>
|
||||
</item>
|
||||
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||
<preferred-size width="150" height="-1" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||
<preferred-size width="150" height="50" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||
<preferred-size width="200" height="200" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||
<preferred-size width="200" height="200" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.svg" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
|
||||
</item>
|
||||
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
|
||||
<preferred-size width="-1" height="20" />
|
||||
</default-constraints>
|
||||
</item>
|
||||
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
|
||||
</item>
|
||||
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
|
||||
</item>
|
||||
</group>
|
||||
</component>
|
||||
</project>
|
@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
@ -1,3 +1,4 @@
|
||||
{
|
||||
"java.compile.nullAnalysis.mode": "automatic"
|
||||
"java.compile.nullAnalysis.mode": "automatic",
|
||||
"java.configuration.updateBuildConfiguration": "interactive"
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,19 +0,0 @@
|
||||
D:\yys\学习资料?\大二下\软工\大作业\software_teamwork\珞珈岛-项目相关文件\luojia-island\common\src\main\java\com\luojia_channel\common\advice\GlobalExceptionHandler.java
|
||||
D:\yys\学习资料?\大二下\软工\大作业\software_teamwork\珞珈岛-项目相关文件\luojia-island\common\src\main\java\com\luojia_channel\common\config\MybatisConfig.java
|
||||
D:\yys\学习资料?\大二下\软工\大作业\software_teamwork\珞珈岛-项目相关文件\luojia-island\common\src\main\java\com\luojia_channel\common\config\OpenApiConfig.java
|
||||
D:\yys\学习资料?\大二下\软工\大作业\software_teamwork\珞珈岛-项目相关文件\luojia-island\common\src\main\java\com\luojia_channel\common\config\RedisConfig.java
|
||||
D:\yys\学习资料?\大二下\软工\大作业\software_teamwork\珞珈岛-项目相关文件\luojia-island\common\src\main\java\com\luojia_channel\common\config\WebMvcConfig.java
|
||||
D:\yys\学习资料?\大二下\软工\大作业\software_teamwork\珞珈岛-项目相关文件\luojia-island\common\src\main\java\com\luojia_channel\common\constants\RedisConstant.java
|
||||
D:\yys\学习资料?\大二下\软工\大作业\software_teamwork\珞珈岛-项目相关文件\luojia-island\common\src\main\java\com\luojia_channel\common\domain\page\PageRequest.java
|
||||
D:\yys\学习资料?\大二下\软工\大作业\software_teamwork\珞珈岛-项目相关文件\luojia-island\common\src\main\java\com\luojia_channel\common\domain\page\PageResponse.java
|
||||
D:\yys\学习资料?\大二下\软工\大作业\software_teamwork\珞珈岛-项目相关文件\luojia-island\common\src\main\java\com\luojia_channel\common\domain\Result.java
|
||||
D:\yys\学习资料?\大二下\软工\大作业\software_teamwork\珞珈岛-项目相关文件\luojia-island\common\src\main\java\com\luojia_channel\common\domain\UserDTO.java
|
||||
D:\yys\学习资料?\大二下\软工\大作业\software_teamwork\珞珈岛-项目相关文件\luojia-island\common\src\main\java\com\luojia_channel\common\exception\BaseException.java
|
||||
D:\yys\学习资料?\大二下\软工\大作业\software_teamwork\珞珈岛-项目相关文件\luojia-island\common\src\main\java\com\luojia_channel\common\exception\FileException.java
|
||||
D:\yys\学习资料?\大二下\软工\大作业\software_teamwork\珞珈岛-项目相关文件\luojia-island\common\src\main\java\com\luojia_channel\common\exception\PostException.java
|
||||
D:\yys\学习资料?\大二下\软工\大作业\software_teamwork\珞珈岛-项目相关文件\luojia-island\common\src\main\java\com\luojia_channel\common\exception\UserException.java
|
||||
D:\yys\学习资料?\大二下\软工\大作业\software_teamwork\珞珈岛-项目相关文件\luojia-island\common\src\main\java\com\luojia_channel\common\interceptor\AuthInterceptor.java
|
||||
D:\yys\学习资料?\大二下\软工\大作业\software_teamwork\珞珈岛-项目相关文件\luojia-island\common\src\main\java\com\luojia_channel\common\utils\JWTUtil.java
|
||||
D:\yys\学习资料?\大二下\软工\大作业\software_teamwork\珞珈岛-项目相关文件\luojia-island\common\src\main\java\com\luojia_channel\common\utils\PageUtil.java
|
||||
D:\yys\学习资料?\大二下\软工\大作业\software_teamwork\珞珈岛-项目相关文件\luojia-island\common\src\main\java\com\luojia_channel\common\utils\RedisUtil.java
|
||||
D:\yys\学习资料?\大二下\软工\大作业\software_teamwork\珞珈岛-项目相关文件\luojia-island\common\src\main\java\com\luojia_channel\common\utils\UserContext.java
|
@ -0,0 +1 @@
|
||||
LuojiaChannelApplication.java
|
@ -0,0 +1,81 @@
|
||||
package com.luojia_channel.modules.admin.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 管理员评论DTO
|
||||
*/
|
||||
@Data
|
||||
public class AdminCommentDTO {
|
||||
/**
|
||||
* 评论ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 评论内容
|
||||
*/
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 用户头像
|
||||
*/
|
||||
private String userAvatar;
|
||||
|
||||
/**
|
||||
* 帖子ID
|
||||
*/
|
||||
private Long postId;
|
||||
|
||||
/**
|
||||
* 帖子标题
|
||||
*/
|
||||
private String postTitle;
|
||||
|
||||
/**
|
||||
* 父评论ID
|
||||
*/
|
||||
private Long parentCommentId;
|
||||
|
||||
/**
|
||||
* 顶级评论ID
|
||||
*/
|
||||
private Long topId;
|
||||
|
||||
/**
|
||||
* 回复用户名
|
||||
*/
|
||||
private String replyUsername;
|
||||
|
||||
/**
|
||||
* 点赞数
|
||||
*/
|
||||
private Integer likeCount;
|
||||
|
||||
/**
|
||||
* 回复数
|
||||
*/
|
||||
private Integer replyCount;
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
package com.luojia_channel.modules.admin.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 管理员用户DTO - 仅包含管理员可见的非隐私信息
|
||||
*/
|
||||
@Data
|
||||
public class AdminUserDTO {
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 头像URL
|
||||
*/
|
||||
private String avatar;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 用户状态(1正常 2冻结)
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 用户角色(1普通用户 2管理员 3超级管理员)
|
||||
*/
|
||||
private Integer role;
|
||||
|
||||
/**
|
||||
* 用户积分
|
||||
*/
|
||||
private Integer integral;
|
||||
|
||||
/**
|
||||
* 发帖数量
|
||||
*/
|
||||
private Integer postCount;
|
||||
|
||||
/**
|
||||
* 评论数量
|
||||
*/
|
||||
private Integer commentCount;
|
||||
|
||||
/**
|
||||
* 粉丝数量
|
||||
*/
|
||||
private Integer followerCount;
|
||||
|
||||
/**
|
||||
* 关注数量
|
||||
*/
|
||||
private Integer followingCount;
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
package com.luojia_channel.modules.admin.service;
|
||||
|
||||
import com.luojia_channel.common.domain.page.PageResponse;
|
||||
import com.luojia_channel.modules.admin.dto.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 管理员服务接口
|
||||
*/
|
||||
public interface AdminService {
|
||||
/**
|
||||
* 获取系统总览数据
|
||||
* @return 总览数据
|
||||
*/
|
||||
AdminOverviewDTO getOverview();
|
||||
|
||||
/**
|
||||
* 获取用户列表
|
||||
* @param page 页码
|
||||
* @param size 每页数量
|
||||
* @param keyword 搜索关键词
|
||||
* @param role 角色
|
||||
* @param status 状态
|
||||
* @return 用户列表分页结果
|
||||
*/
|
||||
PageResponse<AdminUserDTO> getUserList(Integer page, Integer size, String keyword, Integer role, Integer status);
|
||||
|
||||
/**
|
||||
* 修改用户状态
|
||||
* @param id 用户ID
|
||||
* @param status 状态
|
||||
*/
|
||||
void changeUserStatus(Long id, Integer status);
|
||||
|
||||
/**
|
||||
* 修改用户角色
|
||||
* @param id 用户ID
|
||||
* @param role 角色
|
||||
*/
|
||||
void changeUserRole(Long id, Integer role);
|
||||
|
||||
/**
|
||||
* 获取帖子列表
|
||||
* @param page 页码
|
||||
* @param size 每页数量
|
||||
* @param keyword 搜索关键词
|
||||
* @param categoryId 分类ID
|
||||
* @param status 状态
|
||||
* @return 帖子列表分页结果
|
||||
*/
|
||||
PageResponse<AdminPostDTO> getPostList(Integer page, Integer size, String keyword, Long categoryId, Integer status);
|
||||
|
||||
/**
|
||||
* 删除帖子
|
||||
* @param id 帖子ID
|
||||
*/
|
||||
void deletePost(Long id);
|
||||
|
||||
/**
|
||||
* 修改帖子状态
|
||||
* @param id 帖子ID
|
||||
* @param action 操作类型
|
||||
*/
|
||||
void changePostStatus(Long id, Integer action);
|
||||
|
||||
/**
|
||||
* 获取评论列表
|
||||
* @param page 页码
|
||||
* @param size 每页数量
|
||||
* @param keyword 搜索关键词
|
||||
* @param postId 帖子ID
|
||||
* @return 评论列表分页结果
|
||||
*/
|
||||
PageResponse<AdminCommentDTO> getCommentList(Integer page, Integer size, String keyword, Long postId);
|
||||
|
||||
/**
|
||||
* 删除评论
|
||||
* @param id 评论ID
|
||||
*/
|
||||
void deleteComment(Long id);
|
||||
|
||||
/**
|
||||
* 获取用户统计数据
|
||||
* @param type 统计类型
|
||||
* @param startDate 开始日期
|
||||
* @param endDate 结束日期
|
||||
* @return 统计数据
|
||||
*/
|
||||
Map<String, Object> getUserStatistics(String type, String startDate, String endDate);
|
||||
|
||||
/**
|
||||
* 获取帖子统计数据
|
||||
* @param type 统计类型
|
||||
* @param startDate 开始日期
|
||||
* @param endDate 结束日期
|
||||
* @return 统计数据
|
||||
*/
|
||||
Map<String, Object> getPostStatistics(String type, String startDate, String endDate);
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
package com.luojia_channel.modules.feedback.config;
|
||||
|
||||
import org.springframework.amqp.core.*;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class FeedbackRabbitMQConfig {
|
||||
|
||||
// 反馈工单交换机
|
||||
public static final String FEEDBACK_EXCHANGE = "feedback.exchange";
|
||||
|
||||
// 延迟队列 - 消息先进入此队列,过期后转发到死信队列
|
||||
public static final String FEEDBACK_DELAY_QUEUE = "feedback.delay.queue";
|
||||
|
||||
// 死信交换机 - 延迟队列的死信会转发到此交换机
|
||||
public static final String FEEDBACK_DLX_EXCHANGE = "feedback.dlx.exchange";
|
||||
|
||||
// 死信队列 - 最终消费者监听此队列
|
||||
public static final String FEEDBACK_DLX_QUEUE = "feedback.dlx.queue";
|
||||
|
||||
// 路由键
|
||||
public static final String FEEDBACK_ROUTING_KEY = "feedback.routing.key";
|
||||
|
||||
// 声明反馈交换机
|
||||
@Bean
|
||||
DirectExchange feedbackExchange() {
|
||||
return new DirectExchange(FEEDBACK_EXCHANGE, true, false);
|
||||
}
|
||||
|
||||
// 声明死信交换机
|
||||
@Bean
|
||||
DirectExchange feedbackDlxExchange() {
|
||||
return new DirectExchange(FEEDBACK_DLX_EXCHANGE, true, false);
|
||||
}
|
||||
|
||||
// 声明延迟队列,并绑定到死信交换机
|
||||
@Bean
|
||||
Queue feedbackDelayQueue() {
|
||||
return QueueBuilder.durable(FEEDBACK_DELAY_QUEUE)
|
||||
.withArgument("x-dead-letter-exchange", FEEDBACK_DLX_EXCHANGE)
|
||||
.withArgument("x-dead-letter-routing-key", FEEDBACK_ROUTING_KEY)
|
||||
.build();
|
||||
}
|
||||
|
||||
// 声明死信队列
|
||||
@Bean
|
||||
Queue feedbackDlxQueue() {
|
||||
return new Queue(FEEDBACK_DLX_QUEUE, true);
|
||||
}
|
||||
|
||||
// 绑定延迟队列到反馈交换机
|
||||
@Bean
|
||||
Binding feedbackDelayBinding() {
|
||||
return BindingBuilder.bind(feedbackDelayQueue())
|
||||
.to(feedbackExchange())
|
||||
.with(FEEDBACK_ROUTING_KEY);
|
||||
}
|
||||
|
||||
// 绑定死信队列到死信交换机
|
||||
@Bean
|
||||
Binding feedbackDlxBinding() {
|
||||
return BindingBuilder.bind(feedbackDlxQueue())
|
||||
.to(feedbackDlxExchange())
|
||||
.with(FEEDBACK_ROUTING_KEY);
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
package com.luojia_channel.modules.feedback.controller;
|
||||
|
||||
import com.luojia_channel.common.domain.Result;
|
||||
import com.luojia_channel.common.domain.page.PageRequest;
|
||||
import com.luojia_channel.common.domain.page.PageResponse;
|
||||
import com.luojia_channel.common.exception.UserException;
|
||||
import com.luojia_channel.common.utils.UserContext;
|
||||
import com.luojia_channel.modules.feedback.dto.FeedbackTicketBasicInfoDTO;
|
||||
import com.luojia_channel.modules.feedback.dto.FeedbackTicketPageQueryDTO;
|
||||
import com.luojia_channel.modules.feedback.entity.FeedbackTicket;
|
||||
import com.luojia_channel.modules.feedback.service.FeedbackTicketService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/feedback")
|
||||
@Tag(name = "反馈工单模块", description = "反馈工单相关接口")
|
||||
@RequiredArgsConstructor
|
||||
public class FeedbackTicketController {
|
||||
|
||||
private final FeedbackTicketService feedbackTicketService;
|
||||
|
||||
@PostMapping
|
||||
@Operation(summary = "创建反馈工单", description = "用户创建反馈工单")
|
||||
public Result<Long> createFeedbackTicket(@RequestBody FeedbackTicket feedbackTicket) {
|
||||
Long id = feedbackTicketService.createFeedbackTicket(feedbackTicket);
|
||||
return Result.success(id);
|
||||
}
|
||||
|
||||
@PutMapping
|
||||
@Operation(summary = "编辑反馈工单", description = "编辑已有的反馈工单")
|
||||
public Result<Void> updateFeedbackTicket(@RequestBody FeedbackTicket feedbackTicket) {
|
||||
feedbackTicketService.updateFeedbackTicket(feedbackTicket);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@GetMapping("/of/me")
|
||||
@Operation(summary = "个人反馈工单查询", description = "查询当前用户的反馈工单")
|
||||
public Result<List<FeedbackTicket>> getPersonalFeedbackTickets() {
|
||||
Long userId = UserContext.getUserId();
|
||||
if(userId == null){
|
||||
throw new UserException("用户未登录");
|
||||
}
|
||||
List<FeedbackTicket> tickets = feedbackTicketService.getPersonalFeedbackTickets(userId);
|
||||
return Result.success(tickets);
|
||||
}
|
||||
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "分页查询反馈工单", description = "分页查询反馈工单列表")
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "200", description = "获取成功"),
|
||||
@ApiResponse(responseCode = "500", description = "获取失败,请稍后重试")
|
||||
})
|
||||
public Result<PageResponse<FeedbackTicketBasicInfoDTO>> pageFeedbackTicket(FeedbackTicketPageQueryDTO feedbackTicketPageQueryDTO) {
|
||||
PageResponse<FeedbackTicketBasicInfoDTO> pageResponse = feedbackTicketService.pageFeedbackTicket(feedbackTicketPageQueryDTO);
|
||||
return Result.success(pageResponse);
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package com.luojia_channel.modules.feedback.entity;
|
||||
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@TableName("feedback_ticket")
|
||||
public class FeedbackTicket {
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
private Long userId;
|
||||
private String content;
|
||||
private String feedbackType;
|
||||
private Integer status;
|
||||
private String contactInfo;
|
||||
private LocalDateTime createTime;
|
||||
private LocalDateTime handleTime;
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package com.luojia_channel.modules.feedback.mapper;
|
||||
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.luojia_channel.modules.feedback.entity.FeedbackTicket;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface FeedbackTicketMapper extends BaseMapper<FeedbackTicket> {
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package com.luojia_channel.modules.feedback.mq.domain;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class DelayHandleTicketMessage {
|
||||
private Long id;
|
||||
private Long userId;
|
||||
private String content;
|
||||
private String feedbackType;
|
||||
private Integer status;
|
||||
private String contactInfo;
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package com.luojia_channel.modules.feedback.mq.producer;
|
||||
|
||||
|
||||
import com.luojia_channel.modules.feedback.config.FeedbackRabbitMQConfig;
|
||||
import com.luojia_channel.modules.feedback.mq.domain.DelayHandleTicketMessage;
|
||||
import com.luojia_channel.modules.message.mq.AbstractSendProduceTemplate;
|
||||
import com.luojia_channel.modules.message.mq.BaseSendExtendDTO;
|
||||
import com.luojia_channel.modules.message.mq.MessageWrapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class FeedbackMessageProducer extends AbstractSendProduceTemplate<DelayHandleTicketMessage>{
|
||||
|
||||
public FeedbackMessageProducer(@Autowired RabbitTemplate rabbitTemplate){
|
||||
super(rabbitTemplate);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BaseSendExtendDTO buildBaseSendParam(DelayHandleTicketMessage messageSendEvent) {
|
||||
return BaseSendExtendDTO.builder()
|
||||
.eventName("DelayHandleTicketMessageEvent")
|
||||
.exchange(FeedbackRabbitMQConfig.FEEDBACK_EXCHANGE)
|
||||
.routingKey(FeedbackRabbitMQConfig.FEEDBACK_ROUTING_KEY)
|
||||
.keys(messageSendEvent.getId().toString())
|
||||
.delay(24*60*60*1000L) //延迟消息是1天
|
||||
.build();
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
package com.luojia_channel.modules.feedback.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.luojia_channel.modules.feedback.dto.FeedbackTicketBasicInfoDTO;
|
||||
import com.luojia_channel.modules.feedback.dto.FeedbackTicketPageQueryDTO;
|
||||
import com.luojia_channel.modules.feedback.entity.FeedbackTicket;
|
||||
import com.luojia_channel.common.domain.page.PageRequest;
|
||||
import com.luojia_channel.common.domain.page.PageResponse;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface FeedbackTicketService extends IService<FeedbackTicket> {
|
||||
/**
|
||||
* 创建反馈工单
|
||||
* @param feedbackTicket 反馈工单实体
|
||||
* @return 工单 ID
|
||||
*/
|
||||
Long createFeedbackTicket(FeedbackTicket feedbackTicket);
|
||||
|
||||
/**
|
||||
* 编辑反馈工单
|
||||
* @param feedbackTicket 反馈工单实体
|
||||
*/
|
||||
void updateFeedbackTicket(FeedbackTicket feedbackTicket);
|
||||
|
||||
/**
|
||||
* 个人反馈工单查询
|
||||
* @param userId 用户 ID
|
||||
* @return 反馈工单列表
|
||||
*/
|
||||
List<FeedbackTicket> getPersonalFeedbackTickets(Long userId);
|
||||
|
||||
/**
|
||||
* 分页查询反馈工单
|
||||
* @param feedbackTicketPageQueryDTO 分页查询参数
|
||||
* @return 分页结果
|
||||
*/
|
||||
PageResponse<FeedbackTicketBasicInfoDTO> pageFeedbackTicket(FeedbackTicketPageQueryDTO feedbackTicketPageQueryDTO);
|
||||
|
||||
/**
|
||||
* 处理延时反馈工单
|
||||
* @param ticketId 工单ID
|
||||
*/
|
||||
void processDelayedFeedback(Long ticketId);
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
package com.luojia_channel.modules.feedback.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.luojia_channel.common.domain.page.PageRequest;
|
||||
import com.luojia_channel.common.domain.page.PageResponse;
|
||||
import com.luojia_channel.modules.feedback.dto.FeedbackTicketBasicInfoDTO;
|
||||
import com.luojia_channel.modules.feedback.dto.FeedbackTicketPageQueryDTO;
|
||||
import com.luojia_channel.modules.feedback.entity.FeedbackTicket;
|
||||
import com.luojia_channel.modules.feedback.mapper.FeedbackTicketMapper;
|
||||
import com.luojia_channel.modules.feedback.mq.domain.DelayHandleTicketMessage;
|
||||
import com.luojia_channel.modules.feedback.mq.producer.FeedbackMessageProducer;
|
||||
import com.luojia_channel.modules.feedback.service.FeedbackTicketService;
|
||||
import com.luojia_channel.modules.user.entity.User;
|
||||
import com.luojia_channel.modules.user.mapper.UserMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class FeedbackTicketServiceImpl extends ServiceImpl<FeedbackTicketMapper, FeedbackTicket> implements FeedbackTicketService {
|
||||
|
||||
private final UserMapper userMapper;
|
||||
private final FeedbackMessageProducer feedbackMessageProducer;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Long createFeedbackTicket(FeedbackTicket feedbackTicket) {
|
||||
feedbackTicket.setCreateTime(LocalDateTime.now());
|
||||
feedbackTicket.setStatus(1);
|
||||
if(!save(feedbackTicket))
|
||||
throw new RuntimeException("保存工单失败");
|
||||
// 发送延时消息
|
||||
feedbackMessageProducer.sendMessage(BeanUtil.copyProperties(feedbackTicket, DelayHandleTicketMessage.class));
|
||||
return feedbackTicket.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateFeedbackTicket(FeedbackTicket feedbackTicket) {
|
||||
updateById(feedbackTicket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FeedbackTicket> getPersonalFeedbackTickets(Long userId) {
|
||||
LambdaQueryWrapper<FeedbackTicket> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(FeedbackTicket::getUserId, userId);
|
||||
return list(queryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResponse<FeedbackTicketBasicInfoDTO> pageFeedbackTicket(FeedbackTicketPageQueryDTO feedbackTicketPageQueryDTO) {
|
||||
LambdaQueryWrapper<FeedbackTicket> queryWrapper = new LambdaQueryWrapper<>();
|
||||
if (feedbackTicketPageQueryDTO.getFeedbackType() != null) {
|
||||
queryWrapper.eq(FeedbackTicket::getFeedbackType, feedbackTicketPageQueryDTO.getFeedbackType());
|
||||
}
|
||||
if (feedbackTicketPageQueryDTO.getStatus() != null) {
|
||||
queryWrapper.eq(FeedbackTicket::getStatus, feedbackTicketPageQueryDTO.getStatus());
|
||||
}
|
||||
queryWrapper.orderByDesc(FeedbackTicket::getCreateTime);
|
||||
|
||||
Page<FeedbackTicket> page = new Page<>(feedbackTicketPageQueryDTO.getCurrent(), feedbackTicketPageQueryDTO.getSize());
|
||||
IPage<FeedbackTicket> feedbackTicketPage = baseMapper.selectPage(page, queryWrapper);
|
||||
|
||||
List<Long> userIds = new ArrayList<>();
|
||||
feedbackTicketPage.getRecords().forEach(ticket -> userIds.add(ticket.getUserId()));
|
||||
List<User> users = userMapper.selectBatchIds(userIds);
|
||||
Map<Long, User> userMap = users.stream()
|
||||
.collect(Collectors.toMap(User::getId, user -> user));
|
||||
|
||||
List<FeedbackTicketBasicInfoDTO> feedbackTicketBasicInfoDTOS = new ArrayList<>();
|
||||
feedbackTicketPage.getRecords().forEach(ticket -> {
|
||||
FeedbackTicketBasicInfoDTO dto = new FeedbackTicketBasicInfoDTO();
|
||||
BeanUtil.copyProperties(ticket, dto);
|
||||
User user = userMap.getOrDefault(ticket.getUserId(), new User());
|
||||
dto.setUserName(user.getUsername());
|
||||
dto.setUserAvatar(user.getAvatar());
|
||||
feedbackTicketBasicInfoDTOS.add(dto);
|
||||
});
|
||||
|
||||
return PageResponse.<FeedbackTicketBasicInfoDTO>builder()
|
||||
.current(feedbackTicketPage.getCurrent())
|
||||
.size(feedbackTicketPage.getSize())
|
||||
.total(feedbackTicketPage.getTotal())
|
||||
.records(feedbackTicketBasicInfoDTOS)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processDelayedFeedback(Long ticketId) {
|
||||
// 查询工单
|
||||
FeedbackTicket ticket = getById(ticketId);
|
||||
if (ticket == null || ticket.getStatus().equals(3)) {
|
||||
return;
|
||||
}
|
||||
// 处理延时任务,更新工单状态为超时
|
||||
ticket.setStatus(4); //
|
||||
updateById(ticket);
|
||||
// TODO 向管理员发送消息
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
package com.luojia_channel.modules.post.algorithm;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.luojia_channel.common.utils.RedisUtil;
|
||||
import com.luojia_channel.modules.post.dto.resp.PostBasicInfoDTO;
|
||||
import com.luojia_channel.modules.post.entity.Comment;
|
||||
import com.luojia_channel.modules.post.entity.Post;
|
||||
import com.luojia_channel.modules.post.mapper.CommentMapper;
|
||||
import com.luojia_channel.modules.post.mapper.PostMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class PostSelector {
|
||||
|
||||
private final PostMapper postMapper;
|
||||
private final CommentMapper commentMapper;
|
||||
private final RedisUtil redisUtil;
|
||||
|
||||
public void calculatePostScore(Post post){
|
||||
long hours = calculateHoursSince(post.getCreateTime());
|
||||
|
||||
double likes = post.getLikeCount();
|
||||
double comments = post.getCommentCount();
|
||||
double favorites = post.getFavoriteCount();
|
||||
|
||||
double newScore = (1 + likes + comments*0.7 + favorites*0.5)
|
||||
/ Math.pow(1 + hours/24.0, 1.8);
|
||||
|
||||
redisUtil.zAdd("post:hot:"+post.getCategoryId(), post.getId(), newScore);
|
||||
redisUtil.zAdd("post:hot:all", post.getId(), newScore);
|
||||
}
|
||||
|
||||
public void calculateCommentScore(Comment comment){
|
||||
long hours = calculateHoursSince(comment.getCreateTime());
|
||||
|
||||
double likes = comment.getLikeCount();
|
||||
double replies = comment.getReplyCount();
|
||||
double newScore = (1 + likes + replies*0.7)
|
||||
/ Math.pow(1 + hours/24.0, 1.8);
|
||||
|
||||
if(comment.getId().equals(comment.getTopId())) {
|
||||
redisUtil.zAdd("post:comment_by_hot:" + comment.getPostId(), comment.getId(), newScore);
|
||||
} else {
|
||||
redisUtil.zAdd("comment:reply_by_hot:" + comment.getTopId(), comment.getId(), newScore);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新帖子热度分数
|
||||
public void updatePostScore(Long postId) {
|
||||
Post post = postMapper.selectById(postId);
|
||||
if (post == null) return;
|
||||
calculatePostScore(post);
|
||||
}
|
||||
|
||||
// 更新评论热度分数
|
||||
public void updateCommentScore(Long commentId) {
|
||||
Comment comment = commentMapper.selectById(commentId);
|
||||
if(comment == null) return;
|
||||
calculateCommentScore(comment);
|
||||
}
|
||||
|
||||
// 计算从指定时间到现在经过的小时数
|
||||
public long calculateHoursSince(LocalDateTime startTime) {
|
||||
if (startTime == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Instant startInstant = startTime.atZone(ZoneId.systemDefault()).toInstant();
|
||||
Instant nowInstant = Instant.now();
|
||||
|
||||
long millisDiff = Duration.between(startInstant, nowInstant).toMillis();
|
||||
return TimeUnit.HOURS.convert(millisDiff, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
// TODO 自定义首页帖子算法
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,91 @@
|
||||
package com.luojia_channel.modules.post.task;
|
||||
|
||||
import com.luojia_channel.common.utils.RedisUtil;
|
||||
import com.luojia_channel.modules.post.algorithm.PostSelector;
|
||||
import com.luojia_channel.modules.post.entity.Comment;
|
||||
import com.luojia_channel.modules.post.entity.Post;
|
||||
import com.luojia_channel.modules.post.mapper.CommentMapper;
|
||||
import com.luojia_channel.modules.post.mapper.PostMapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class UpdateScoreTask {
|
||||
|
||||
private static final int BATCH_SIZE = 100;
|
||||
// 每半小时更新热度
|
||||
private static final long POST_UPDATE_INTERVAL = 30 * 60;
|
||||
private static final long COMMENT_UPDATE_INTERVAL = 30 * 60;
|
||||
|
||||
private final PostSelector postSelector;
|
||||
private final PostMapper postMapper;
|
||||
private final CommentMapper commentMapper;
|
||||
private final RedisUtil redisUtil;
|
||||
|
||||
// 定时更新帖子热度分数
|
||||
@Scheduled(fixedRate = POST_UPDATE_INTERVAL * 1000)
|
||||
public void updatePostScores() {
|
||||
// 扩大更新范围到最近30天的帖子
|
||||
LocalDateTime startTime = LocalDateTime.now().minusDays(30);
|
||||
|
||||
LambdaQueryWrapper<Post> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.ge(Post::getCreateTime, startTime);
|
||||
|
||||
long totalPosts = postMapper.selectCount(queryWrapper);
|
||||
long batches = (totalPosts + BATCH_SIZE - 1) / BATCH_SIZE;
|
||||
|
||||
for (int i = 0; i < batches; i++) {
|
||||
queryWrapper.last("LIMIT " + i * BATCH_SIZE + ", " + BATCH_SIZE);
|
||||
List<Post> posts = postMapper.selectList(queryWrapper);
|
||||
posts.forEach(post -> postSelector.updatePostScore(post.getId()));
|
||||
}
|
||||
}
|
||||
|
||||
// 定时更新评论热度分数
|
||||
@Scheduled(fixedRate = COMMENT_UPDATE_INTERVAL * 1000)
|
||||
public void updateCommentScores() {
|
||||
// 扩大更新范围到最近15天的评论
|
||||
LocalDateTime startTime = LocalDateTime.now().minusDays(15);
|
||||
|
||||
LambdaQueryWrapper<Comment> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.ge(Comment::getCreateTime, startTime);
|
||||
|
||||
long totalComments = commentMapper.selectCount(queryWrapper);
|
||||
long batches = (totalComments + BATCH_SIZE - 1) / BATCH_SIZE;
|
||||
|
||||
for (int i = 0; i < batches; i++) {
|
||||
queryWrapper.last("LIMIT " + i * BATCH_SIZE + ", " + BATCH_SIZE);
|
||||
List<Comment> comments = commentMapper.selectList(queryWrapper);
|
||||
comments.forEach(comment -> postSelector.updateCommentScore(comment.getId()));
|
||||
}
|
||||
}
|
||||
|
||||
// 定期清理过期的缓存数据
|
||||
@Scheduled(cron = "0 0 4 * * ?") // 每天凌晨4点执行
|
||||
public void cleanExpiredData() {
|
||||
LocalDateTime expiredTime = LocalDateTime.now().minusDays(60);
|
||||
|
||||
// 清理过期的帖子缓存
|
||||
LambdaQueryWrapper<Post> postQueryWrapper = new LambdaQueryWrapper<>();
|
||||
postQueryWrapper.le(Post::getCreateTime, expiredTime);
|
||||
List<Post> expiredPosts = postMapper.selectList(postQueryWrapper);
|
||||
expiredPosts.forEach(post -> {
|
||||
redisUtil.zRemove("post:hot:", post.getId());
|
||||
redisUtil.zRemove("post:time:", post.getId());
|
||||
});
|
||||
|
||||
// 清理过期的评论缓存
|
||||
LambdaQueryWrapper<Comment> commentQueryWrapper = new LambdaQueryWrapper<>();
|
||||
commentQueryWrapper.le(Comment::getCreateTime, expiredTime);
|
||||
List<Comment> expiredComments = commentMapper.selectList(commentQueryWrapper);
|
||||
expiredComments.forEach(comment -> {
|
||||
// 评论相关缓存清理
|
||||
});
|
||||
}
|
||||
}
|
@ -1 +0,0 @@
|
||||
lj:
|
@ -1,56 +0,0 @@
|
||||
#本地开发环境
|
||||
# lj:
|
||||
# db:
|
||||
# host: localhost
|
||||
# password: 123456
|
||||
# redis:
|
||||
# host: localhost
|
||||
# port: 6379
|
||||
# password: 123456
|
||||
# rabbitmq:
|
||||
# host: localhost
|
||||
# port: 15672
|
||||
# username: root
|
||||
# password: 123456
|
||||
# minio:
|
||||
# endpoint: http://localhost:9000
|
||||
# accessKey: minioadmin
|
||||
# secretKey: minioadmin
|
||||
|
||||
#lj:
|
||||
# db:
|
||||
# host: 192.168.59.129
|
||||
# password: Forely123!
|
||||
# redis:
|
||||
# host: 192.168.59.129
|
||||
# port: 6379
|
||||
# password: Forely123!
|
||||
# rabbitmq:
|
||||
# host: 192.168.59.129
|
||||
# port: 5672
|
||||
# username: admin
|
||||
# password: Forely123!
|
||||
# minio:
|
||||
# endpoint: http://192.168.59.129:9000
|
||||
# accessKey: forely
|
||||
# secretKey: Forely123!
|
||||
|
||||
|
||||
|
||||
lj:
|
||||
db:
|
||||
host: 192.168.125.128
|
||||
password: MySQL@5678
|
||||
redis:
|
||||
host: 192.168.125.128
|
||||
port: 6379
|
||||
password: Redis@9012
|
||||
rabbitmq:
|
||||
host: 192.168.125.128
|
||||
port: 5672
|
||||
username: rabbit_admin
|
||||
password: Rabbit@3456
|
||||
minio:
|
||||
endpoint: http://192.168.125.128:9000
|
||||
accessKey: minio_admin
|
||||
secretKey: Minio@1234
|
@ -1,66 +0,0 @@
|
||||
server:
|
||||
port: 8081
|
||||
springdoc:
|
||||
api-docs:
|
||||
path: /openapi/luojia-channel
|
||||
swagger-ui:
|
||||
path: /swagger-ui.html
|
||||
disable-swagger-default-url: true
|
||||
tags-sorter: alpha
|
||||
operations-sorter: alpha
|
||||
packages-to-scan: com.luojia_channel.modules
|
||||
paths-to-match: /user/**, /post/**, /comment/**, /message/**, /follow/**, /file/**
|
||||
spring:
|
||||
application:
|
||||
name: service
|
||||
profiles:
|
||||
active: local
|
||||
# 数据库
|
||||
datasource:
|
||||
url: jdbc:mysql://${lj.db.host}:3306/luojia_channel?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
username: root
|
||||
password: ${lj.db.password}
|
||||
# redis配置
|
||||
data:
|
||||
redis:
|
||||
host: ${lj.redis.host}
|
||||
port: ${lj.redis.port}
|
||||
password: ${lj.redis.password}
|
||||
lettuce:
|
||||
pool:
|
||||
max-active: 10
|
||||
max-idle: 10
|
||||
min-idle: 1
|
||||
time-between-eviction-runs: 10s
|
||||
# rabbitmq配置
|
||||
rabbitmq:
|
||||
host: ${lj.rabbitmq.host}
|
||||
port: ${lj.rabbitmq.port}
|
||||
username: ${lj.rabbitmq.username}
|
||||
password: ${lj.rabbitmq.password}
|
||||
virtual-host: /
|
||||
listener:
|
||||
simple:
|
||||
acknowledge-mode: manual
|
||||
concurrency: 5
|
||||
max-concurrency: 10
|
||||
prefetch: 1
|
||||
# minio配置
|
||||
minio:
|
||||
endpoint: ${lj.minio.endpoint}
|
||||
accessKey: ${lj.minio.accessKey}
|
||||
secretKey: ${lj.minio.secretKey}
|
||||
|
||||
mybatis-plus:
|
||||
configuration:
|
||||
default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
|
||||
global-config:
|
||||
db-config:
|
||||
update-strategy: not_null
|
||||
id-type: auto
|
||||
mapper-locations: classpath*:mapper/**/*.xml
|
||||
type-aliases-package: com.luojia.luojia_channel.modules.*.entity
|
||||
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue