main #1

Merged
miaozerun merged 6 commits from iVMiku/guidance-backend:main into main 2024-08-09 09:43:59 +08:00
81 changed files with 3682 additions and 61 deletions

17
.idea/dataSources.xml generated Normal file
View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
<data-source source="LOCAL" name="tutorial" uuid="ab32c606-868a-42e7-bd6c-a41e480856c9">
<driver-ref>mysql_aurora_aws</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>software.aws.rds.jdbc.mysql.Driver</jdbc-driver>
<jdbc-url>jdbc:mysql:aws://localhost:3306/tutorial</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.container.port" />
</jdbc-additional-properties>
<working-dir>$ProjectFileDir$</working-dir>
</data-source>
</component>
</project>

2
.idea/encodings.xml generated
View File

@@ -3,6 +3,8 @@
<component name="Encoding">
<file url="file://$PROJECT_DIR$/commons/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/commons/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/community-8073/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/community-8073/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/gateway-8133/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/gateway-8133/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />

2
.idea/misc.xml generated
View File

@@ -8,7 +8,7 @@
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="21" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" project-jdk-name="21" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

65
.idea/mybatisx/templates.xml generated Normal file
View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="TemplatesSettings">
<option name="templateConfigs">
<TemplateContext>
<option name="generateConfig">
<GenerateConfig>
<option name="annotationType" value="MYBATIS_PLUS3" />
<option name="basePackage" value="com.ivmiku.tutorial" />
<option name="basePath" value="src/main/java" />
<option name="classNameStrategy" value="camel" />
<option name="encoding" value="UTF-8" />
<option name="extraClassSuffix" value="" />
<option name="ignoreFieldPrefix" value="" />
<option name="ignoreFieldSuffix" value="" />
<option name="ignoreTablePrefix" value="" />
<option name="ignoreTableSuffix" value="" />
<option name="moduleName" value="community-8073" />
<option name="modulePath" value="$PROJECT_DIR$/community-8073" />
<option name="moduleUIInfoList">
<list>
<ModuleInfoGo>
<option name="basePath" value="${domain.basePath}" />
<option name="configFileName" value="mapperInterface.ftl" />
<option name="configName" value="mapperInterface" />
<option name="encoding" value="${domain.encoding}" />
<option name="fileName" value="${domain.fileName}Mapper" />
<option name="fileNameWithSuffix" value="${domain.fileName}Mapper.java" />
<option name="modulePath" value="$PROJECT_DIR$/community-8073" />
<option name="packageName" value="${domain.basePackage}.mapper" />
</ModuleInfoGo>
<ModuleInfoGo>
<option name="basePath" value="src/main/resources" />
<option name="configFileName" value="mapperXml.ftl" />
<option name="configName" value="mapperXml" />
<option name="encoding" value="${domain.encoding}" />
<option name="fileName" value="${domain.fileName}Mapper" />
<option name="fileNameWithSuffix" value="${domain.fileName}Mapper.xml" />
<option name="modulePath" value="$PROJECT_DIR$/community-8073" />
<option name="packageName" value="mapper" />
</ModuleInfoGo>
</list>
</option>
<option name="needsModel" value="true" />
<option name="relativePackage" value="entity" />
<option name="superClass" value="" />
<option name="tableUIInfoList">
<list>
<TableUIInfo>
<option name="className" value="Usercommunity" />
<option name="tableName" value="usercommunity" />
</TableUIInfo>
</list>
</option>
<option name="templatesName" value="mybatis-plus3" />
<option name="useLombokPlugin" value="true" />
</GenerateConfig>
</option>
<option name="moduleName" value="community-8073" />
<option name="projectPath" value="$PROJECT_DIR$" />
<option name="templateName" value="mybatis-plus3" />
</TemplateContext>
</option>
</component>
</project>

124
.idea/uiDesigner.xml generated Normal file
View File

@@ -0,0 +1,124 @@
<?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>

6
.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View File

@@ -27,5 +27,22 @@
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.21</version>
</dependency>
<!-- spring-boot-starter-test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>3.1.5</version>
</dependency>
<!--feign-micrometer 5-->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-micrometer</artifactId>
<version>12.5</version>
</dependency>
</dependencies>
</project>

173
community-8073/pom.xml Normal file
View File

@@ -0,0 +1,173 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.ivmiku.tutorial</groupId>
<artifactId>first-tutorial</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>community-8073</artifactId>
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- <dependency>-->
<!-- <groupId>io.springfox</groupId>-->
<!-- <artifactId>springfox-boot-starter</artifactId>-->
<!-- <version>3.0.0</version>-->
<!-- </dependency>-->
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>7.0.2</version>
</dependency>
<!-- Swagger 依赖-->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.1.0</version>
</dependency>
<!-- javax.servlet 依赖 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<!-- Sa-Token 权限认证在线文档https://sa-token.cc -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot3-starter</artifactId>
</dependency>
<!-- fastjson2 -->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
</dependency>
<!-- Sa-Token 整合 Redis (使用 jackson 序列化方式) -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-redis-jackson</artifactId>
<version>1.38.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!-- dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.dubbo/dubbo-registry-nacos -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<!--micrometer-tracing指标追踪 1-->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing</artifactId>
</dependency>
<!--micrometer-tracing-bridge-brave适配zipkin的桥接包 2-->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-brave</artifactId>
</dependency>
<!--micrometer-observation 3-->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-observation</artifactId>
</dependency>
<!--zipkin-reporter-brave 5-->
<dependency>
<groupId>io.zipkin.reporter2</groupId>
<artifactId>zipkin-reporter-brave</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-tracing-brave-zipkin-starter</artifactId>
<version>3.2.13</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-miniapp</artifactId>
</dependency>
<dependency>
<groupId>com.ivmiku.tutorial</groupId>
<artifactId>commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>3.0.13</version>
<configuration>
<mainClass>com.ivmiku.tutorial.Main8072</mainClass>
<layout>JAR</layout>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,15 @@
package com.ivmiku.tutorial;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication(exclude = {
org.springframework.boot.actuate.autoconfigure.tracing.zipkin.ZipkinAutoConfiguration.class
})
@MapperScan("com.ivmiku.tutorial.mapper")
public class Main8073 {
public static void main(String[] args) {
SpringApplication.run(Main8073.class, args);
}
}

View File

@@ -0,0 +1,27 @@
package com.ivmiku.tutorial.config;
import io.minio.MinioClient;
import io.minio.errors.InvalidEndpointException;
import io.minio.errors.InvalidPortException;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Data
@Configuration
/*加载yml文件中以minio开头的配置项*/
@ConfigurationProperties(prefix = "minio")
public class MinioConfig {
/*会自动的对应配置项中对应的key*/
private String endpoint;//minio.endpoint
private String accessKey;
private String secretKey;
private Integer port;
/*把官方提供的MinioClient客户端注册到IOC容器中*/
@Bean
public MinioClient getMinioClient() throws InvalidPortException, InvalidEndpointException {
MinioClient minioClient = new MinioClient(getEndpoint(), getPort(), getAccessKey(), getSecretKey(), false);
return minioClient;
}
}

View File

@@ -0,0 +1,256 @@
package com.ivmiku.tutorial.controller;
import cn.dev33.satoken.stp.StpUtil;
import com.ivmiku.tutorial.entity.Comment;
import com.ivmiku.tutorial.response.Result;
import com.ivmiku.tutorial.service.CommentService;
import com.ivmiku.tutorial.service.FileService;
import io.swagger.v3.oas.annotations.Operation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.util.List;
/**
* 评论控制器用于处理评论相关的HTTP请求。
*/
@RestController
@RequestMapping("/comments")
public class CommentController {
private static final Logger logger = LoggerFactory.getLogger(CommentController.class);
@Resource
private CommentService commentService;
@Resource
private FileService fileService;
/**
* 创建评论接口。
*
* @param content 评论内容
* @param postId 帖子的ID
* @param mentionedUserId 提及的用户ID可选
* @param imageFiles 图片文件(可选)
* @param videoFile 视频文件(可选)
* @return 返回操作结果
*/
@PostMapping("/create")
@Operation(summary = "创建评论")
public Result createComment(@RequestParam("content") String content,
@RequestParam("postId") Long postId,
@RequestParam(value = "mentionedUserId", required = false) String mentionedUserId,
@RequestParam(value = "imageFiles", required = false) MultipartFile[] imageFiles,
@RequestParam(value = "videoFile", required = false) MultipartFile videoFile) {
logger.info("创建评论请求开始用户ID{}", StpUtil.getLoginIdAsString());
Comment comment = new Comment();
comment.setUserOpenid(StpUtil.getLoginIdAsString());
comment.setPostId(postId);
comment.setContent(content);
comment.setParentCommentId(0l);
comment.setMentionedUserId(mentionedUserId);
try {
// 上传视频
if (videoFile != null && !videoFile.isEmpty()) {
String uploadResult = fileService.uploadMinio(videoFile);
comment.setVideoUrl(uploadResult);
}
// 上传图片
if (imageFiles != null && imageFiles.length > 0) {
StringBuilder imageUrls = new StringBuilder();
for (MultipartFile file : imageFiles) {
String uploadResult = fileService.uploadMinio(file);
imageUrls.append(uploadResult + ";");
}
comment.setImageUrls(imageUrls.toString());
}
} catch (Exception e) {
logger.error("文件上传失败", e);
return Result.error("文件上传失败");
}
commentService.createComment(comment);
logger.info("评论创建成功评论ID{}", comment.getCommentId());
return Result.ok(comment);
}
/**
* 回复评论接口。
*
* @param parentCommentId 父评论的ID
* @param postId 帖子的ID
* @param content 回复内容
* @param mentionedUserId 提及的用户ID可选
* @param imageFiles 图片文件(可选)
* @param videoFile 视频文件(可选)
* @return 返回操作结果
*/
@PostMapping("/reply")
@Operation(summary = "回复评论")
public Result replyComment(@RequestParam Long parentCommentId,
@RequestParam Long postId,
@RequestParam String content,
@RequestParam(required = false) String mentionedUserId,
@RequestParam(value = "imageFiles", required = false) MultipartFile[] imageFiles,
@RequestParam(value = "videoFile", required = false) MultipartFile videoFile) {
logger.info("回复评论请求开始用户ID{}", StpUtil.getLoginIdAsString());
// 检查父评论是否存在
Comment parentComment = commentService.getCommentById(parentCommentId);
if (parentComment == null) {
logger.warn("父评论ID{}不存在", parentCommentId);
return Result.error("父评论不存在");
}
Comment reply = new Comment();
reply.setUserOpenid(StpUtil.getLoginIdAsString());
reply.setParentCommentId(parentCommentId);
reply.setPostId(postId);
reply.setContent(content);
reply.setMentionedUserId(mentionedUserId);
try {
// 上传视频
if (videoFile != null && !videoFile.isEmpty()) {
String uploadResult = fileService.uploadMinio(videoFile);
reply.setVideoUrl(uploadResult);
}
// 上传图片
if (imageFiles != null && imageFiles.length > 0) {
StringBuilder imageUrls = new StringBuilder();
for (MultipartFile file : imageFiles) {
String uploadResult = fileService.uploadMinio(file);
imageUrls.append(uploadResult + ";");
}
reply.setImageUrls(imageUrls.toString());
}
} catch (Exception e) {
logger.error("文件上传失败", e);
return Result.error("文件上传失败");
}
commentService.createComment(reply);
logger.info("评论回复成功评论ID{}", reply.getCommentId());
return Result.ok(reply);
}
/**
* 获取评论详情接口。
*
* @param id 评论的唯一标识ID
* @return 返回操作结果和评论详情
*/
@GetMapping("/get/{id}")
@Operation(summary = "获取评论详情")
public Result getComment(@PathVariable Long id) {
logger.info("获取评论请求开始评论ID{}", id);
Comment comment = commentService.getCommentById(id);
if (comment != null) {
logger.info("评论获取成功,评论内容:{}", comment.getContent());
} else {
logger.warn("获取评论失败未找到ID为{}的评论", id);
}
return Result.ok(comment);
}
/**
* 更新评论接口。
*
* @param id 要更新的评论的唯一标识ID
* @param comment 更新后的评论数据
* @return 返回操作结果
*/
@PutMapping("/update/{id}")
@Operation(summary = "更新评论")
public Result updateComment(@PathVariable Long id, @RequestBody Comment comment) {
logger.info("更新评论请求开始评论ID{}", id);
String userId = StpUtil.getLoginIdAsString();
commentService.updateComment(id, userId, comment);
logger.info("评论更新成功评论ID{}", id);
return Result.ok();
}
/**
* 删除评论接口。
*
* @param id 要删除的评论的唯一标识ID
* @return 返回操作结果
*/
@DeleteMapping("/delete/{id}")
@Operation(summary = "删除评论")
public Result deleteComment(@PathVariable Long id) {
logger.info("删除评论请求开始评论ID{}", id);
String userId = StpUtil.getLoginIdAsString();
commentService.deleteComment(id, userId);
logger.info("评论删除成功评论ID{}", id);
return Result.ok();
}
/**
* 获取帖子下的所有评论。
*
* @param postId 帖子的唯一标识ID
* @return 返回操作结果和评论列表
*/
@GetMapping("/post/{postId}")
@Operation(summary = "获取帖子下的所有评论")
public Result getPostComments(@PathVariable("postId") Long postId) {
logger.info("获取帖子ID{}的评论列表", postId);
List<Comment> comments = commentService.getPostComments(postId);
return Result.ok(comments);
}
/**
* 获取评论下的所有回复。
*
* @param commentId 评论的唯一标识ID
* @return 返回操作结果和回复列表
*/
@GetMapping("/replies/{commentId}")
@Operation(summary = "获取评论下的所有回复")
public Result getCommentReplies(@PathVariable Long commentId) {
logger.info("获取评论ID{}的回复列表", commentId);
List<Comment> replies = commentService.getCommentReplies(commentId);
return Result.ok(replies);
}
/**
* @评论接口。
*
* @param comment 包含@信息的评论数据
* @return 返回操作结果
*/
@PostMapping("/mention")
@Operation(summary = "@评论")
public Result mentionUser(@RequestBody Comment comment) {
logger.info("用户ID{}提交@评论请求", StpUtil.getLoginIdAsString());
// 检查父评论是否存在如果有父评论ID
if (comment.getParentCommentId() != null) {
Comment parentComment = commentService.getCommentById(comment.getParentCommentId());
if (parentComment == null) {
logger.warn("父评论ID{}不存在", comment.getParentCommentId());
return Result.error("父评论不存在");
}
}
// 检查帖子ID是否存在
if (comment.getPostId() == null) {
logger.warn("帖子ID不能为空");
return Result.error("帖子ID不能为空");
}
comment.setUserOpenid(StpUtil.getLoginIdAsString());
commentService.createComment(comment);
logger.info("@评论创建成功评论ID{}", comment.getCommentId());
return Result.ok();
}
}

View File

@@ -0,0 +1,103 @@
package com.ivmiku.tutorial.controller;
import com.ivmiku.tutorial.entity.Community;
import com.ivmiku.tutorial.response.Result;
import com.ivmiku.tutorial.service.CommunityService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.models.annotations.OpenAPI30;
import org.apiguardian.api.API;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
/**
* CommunityController 是处理社区相关请求的控制器类。
*/
@RestController
@RequestMapping("/communities")
public class CommunityController {
// 使用SLF4J的LoggerFactory来创建一个日志记录器
private static final Logger logger = LoggerFactory.getLogger(CommunityController.class);
@Resource
private CommunityService communityService;
/**
* 创建一个新的社区。
*
* @param community 要创建的社区对象
* @return 创建结果的响应
*/
@PostMapping("/create")
@Operation(summary = "创建社区")
public Result createCommunity(@RequestBody Community community) {
communityService.createCommunity(community); // 调用服务层创建社区
return Result.ok(); // 返回成功结果
}
/**
* 根据ID获取社区信息。
*
* @param id 社区的ID
* @return 包含社区信息的响应
*/
@GetMapping("/get/{id}")
public Result getCommunity(@PathVariable Long id) {
Community community = communityService.getById(id); // 根据ID获取社区信息
return Result.ok(community); // 返回包含社区信息的成功结果
}
/**
* 更新社区信息。
*
* @param id 要更新的社区ID
* @param community 更新后的社区对象
* @return 更新结果的响应
*/
@PutMapping("/update/{id}")
public Result updateCommunity(@PathVariable Long id, @RequestBody Community community) {
communityService.updateCommunity(id, community); // 调用服务层更新社区信息
return Result.ok(); // 返回成功结果
}
/**
* 删除社区。
*
* @param id 要删除的社区ID
* @return 删除结果的响应
*/
@DeleteMapping("/delete/{id}")
public Result deleteCommunity(@PathVariable Long id) {
communityService.deleteCommunity(id); // 调用服务层删除社区
return Result.ok(); // 返回成功结果
}
/**
* 根据name获取社区信息。
*
* @param name 社区的name
* @return 包含社区信息的响应
*/
@GetMapping("/getByName/{name}")
public Result getCommunityByName(@PathVariable String name) {
logger.info("社区名称为: {}", name);
List<Community> communitys = communityService.getByName(name); // 根据ID获取社区信息
return Result.ok(communitys); // 返回包含社区信息的成功结果
}
/**
* 获取所有社区。
*
* @return 包含社区信息的响应
*/
@GetMapping("/list")
public Result getCommunityList() {
List<Community> communities = communityService.getCommunityList(); // 获取社区列表
return Result.ok(communities); // 返回包含社区信息的成功结果
}
}

View File

@@ -0,0 +1,105 @@
package com.ivmiku.tutorial.controller;
import cn.dev33.satoken.stp.StpUtil;
import com.ivmiku.tutorial.response.Result;
import com.ivmiku.tutorial.service.InteractionService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
/**
* InteractionController 是处理用户与帖子的收藏、点赞以及对评论的点赞功能的控制器类。
*/
@Slf4j
@RestController
@RequestMapping("/interaction")
public class InteractionController {
@Resource
private InteractionService interactionService;
/**
* 收藏帖子
*
* @param postId 帖子ID
* @return 操作结果
*/
@PostMapping("/favorite")
public Result favoritePost(@RequestParam Long postId) {
String userOpenid = StpUtil.getLoginIdAsString();
log.info("User {} is favoriting post {}", userOpenid, postId);
interactionService.favoritePost(userOpenid, postId);
return Result.ok();
}
/**
* 对帖子点赞
*
* @param postId 帖子ID
* @return 操作结果
*/
@PostMapping("/likePost")
public Result likePost(@RequestParam Long postId) {
String userOpenid = StpUtil.getLoginIdAsString();
log.info("User {} is liking post {}", userOpenid, postId);
interactionService.likePost(userOpenid, postId);
return Result.ok();
}
/**
* 对评论点赞
*
* @param commentId 评论ID
* @return 操作结果
*/
@PostMapping("/likeComment")
public Result likeComment(@RequestParam Long commentId) {
String userOpenid = StpUtil.getLoginIdAsString();
log.info("User {} is liking comment {}", userOpenid, commentId);
interactionService.likeComment(userOpenid, commentId);
return Result.ok();
}
/**
* 取消收藏帖子
*
* @param postId 帖子ID
* @return 操作结果
*/
@DeleteMapping("/unfavorite")
public Result unfavoritePost(@RequestParam Long postId) {
String userOpenid = StpUtil.getLoginIdAsString();
log.info("User {} is unfavoriting post {}", userOpenid, postId);
interactionService.unfavoritePost(userOpenid, postId);
return Result.ok();
}
/**
* 取消对帖子的点赞
*
* @param postId 帖子ID
* @return 操作结果
*/
@DeleteMapping("/unlikePost")
public Result unlikePost(@RequestParam Long postId) {
String userOpenid = StpUtil.getLoginIdAsString();
log.info("User {} is unliking post {}", userOpenid, postId);
interactionService.unlikePost(userOpenid, postId);
return Result.ok();
}
/**
* 取消对评论的点赞
*
* @param commentId 评论ID
* @return 操作结果
*/
@DeleteMapping("/unlikeComment")
public Result unlikeComment(@RequestParam Long commentId) {
String userOpenid = StpUtil.getLoginIdAsString();
log.info("User {} is unliking comment {}", userOpenid, commentId);
interactionService.unlikeComment(userOpenid, commentId);
return Result.ok();
}
}

View File

@@ -0,0 +1,143 @@
package com.ivmiku.tutorial.controller;
import cn.dev33.satoken.stp.StpUtil;
import com.ivmiku.tutorial.entity.Post;
import com.ivmiku.tutorial.response.Result;
import com.ivmiku.tutorial.service.FileService;
import com.ivmiku.tutorial.service.PostService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.sql.Timestamp;
import java.util.List;
/**
* 帖子控制器用于处理帖子相关的HTTP请求。
*/
@RestController
@RequestMapping("/post")
public class PostController {
private static final Logger logger = LoggerFactory.getLogger(PostController.class);
@Resource
private PostService postService;
@Resource
private FileService fileService;
@PostMapping("/create")
public Result createPost(@RequestParam("title") String title,
@RequestParam("content") String content,
@RequestParam("communityId") Long communityId,
@RequestParam("imageFiles") MultipartFile[] imageFiles,
@RequestParam("videoFile") MultipartFile videoFile) {
String userId = StpUtil.getLoginIdAsString();
logger.info("用户ID{}开始创建帖子", userId);
Post post = new Post();
post.setUserOpenid(userId);
post.setTitle(title);
post.setContent(content);
post.setCommunityId(communityId);
try {
// 上传视频
if (videoFile != null && !videoFile.isEmpty()) {
String uploadResult = fileService.uploadMinio(videoFile);
post.setVideoUrl(uploadResult);
}
// 上传图片
if (imageFiles != null && imageFiles.length > 0) {
StringBuilder imageUrls = new StringBuilder();
for (MultipartFile file : imageFiles) {
String uploadResult = fileService.uploadMinio(file);
imageUrls.append(uploadResult).append(";");
}
post.setImageUrls(imageUrls.toString());
}
} catch (Exception e) {
logger.error("文件上传失败", e);
return Result.error("文件上传失败");
}
postService.createPost(post);
logger.info("用户ID{}的帖子创建成功", userId);
return Result.ok(post);
}
@GetMapping("/get/{id}")
public Result getPost(@PathVariable Long id) {
logger.info("开始获取帖子ID{}的详细信息", id);
Post post = postService.getPostById(id); // 调用服务层根据ID查询帖子
if (post != null) {
logger.info("帖子ID{}的详细信息获取成功", id);
} else {
logger.warn("帖子ID{}不存在", id);
}
return Result.ok(post);
}
@PutMapping("/update/{id}")
public Result updatePost(@PathVariable Long id, @RequestBody Post post) {
String userId = StpUtil.getLoginIdAsString(); // 获取当前登录用户的ID
logger.info("用户ID{}开始更新帖子ID{}", userId, id);
postService.updatePost(id, userId, post); // 调用服务层更新帖子
logger.info("用户ID{}的帖子ID{}更新成功", userId, id);
return Result.ok();
}
@DeleteMapping("/delete/{id}")
public Result deletePost(@PathVariable Long id) {
String userId = StpUtil.getLoginIdAsString(); // 获取当前登录用户的ID
logger.info("用户ID{}开始删除帖子ID{}", userId, id);
postService.deletePost(id, userId); // 调用服务层删除帖子
logger.info("用户ID{}的帖子ID{}删除成功", userId, id);
return Result.ok();
}
/**
* 用户获取自己所有帖子的信息
* @return 当前用户帖子列表
*/
@GetMapping("/getPostList")
public Result getPostList() {
logger.info("开始获取帖子列表");
String userId = StpUtil.getLoginIdAsString(); // 获取当前登录用户的ID
List<Post> posts = postService.getPostList(userId);
return Result.ok(posts); // 调用服务层获取帖子列表
}
/**
* 社区获取自己所有帖子的信息
* @return 当前用户帖子列表
*/
@GetMapping("/getCommunityPostList{communityId}")
public Result getCommunityPostList(@PathVariable("communityId") Long communityId) {
logger.info("开始获取帖子列表");
List<Post> posts = postService.getCommunityPostList(communityId);
return Result.ok(posts); // 调用服务层获取帖子列表
}
/**
* 获取所有官方创建的帖子
* @return
*/
@GetMapping("/official")
public List<Post> getOfficialPosts() {
return postService.getOfficialPosts();
}
/**
* 获取所有非官方创建的帖子
* @return
*/
@GetMapping("/nonOfficial")
public List<Post> getNonOfficialPosts() {
return postService.getNonOfficialPosts();
}
}

View File

@@ -0,0 +1,112 @@
package com.ivmiku.tutorial.controller;
import com.ivmiku.tutorial.entity.Post;
import com.ivmiku.tutorial.entity.PostTag;
import com.ivmiku.tutorial.entity.Tag;
import com.ivmiku.tutorial.response.Result;
import com.ivmiku.tutorial.service.PostTagService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/post-tag")
public class PostTagController {
// 日志记录器,用于记录控制器中的日志信息
private static final Logger logger = LoggerFactory.getLogger(PostTagController.class);
// 通过@Autowired注解自动装配PostTagService服务
@Autowired
private PostTagService postTagService;
/**
* 创建帖子标签接口。
* 用户通过POST请求提交帖子标签数据服务端接收并保存帖子标签。
*
* @param postTag 提交的帖子标签数据
* @return Result 返回操作结果
*/
@PostMapping("/create")
public Result createPostTag(@RequestBody PostTag postTag) {
logger.info("开始创建帖子标签");
postTagService.createPostTag(postTag);
logger.info("帖子标签创建成功ID{}", postTag.getPostTagId());
return Result.ok();
}
/**
* 获取帖子标签详情接口。
* 根据帖子标签ID获取帖子标签的详细信息。
*
* @param id 帖子标签的唯一标识ID
* @return Result 返回操作结果和帖子标签详情
*/
@GetMapping("/get/{id}")
public Result getPostTag(@PathVariable Long id) {
logger.info("开始获取帖子标签ID{}的详细信息", id);
PostTag postTag = postTagService.getPostTagById(id);
if (postTag != null) {
logger.info("帖子标签ID{}的详细信息获取成功", id);
} else {
logger.warn("未找到ID为{}的帖子标签", id);
}
return Result.ok(postTag);
}
/**
* 更新帖子标签接口。
* 用户通过PUT请求提交更新后的帖子标签数据服务端接收并更新帖子标签。
*
* @param id 要更新的帖子标签的唯一标识ID
* @param postTag 更新后的帖子标签数据
* @return Result 返回操作结果
*/
@PutMapping("/update/{id}")
public Result updatePostTag(@PathVariable Long id, @RequestBody PostTag postTag) {
logger.info("开始更新帖子标签ID{}", id);
postTagService.updatePostTag(id, postTag);
logger.info("帖子标签ID{}更新成功", id);
return Result.ok();
}
/**
* 删除帖子标签接口。
* 根据帖子标签ID删除指定的帖子标签。
*
* @param id 要删除的帖子标签的唯一标识ID
* @return Result 返回操作结果
*/
@DeleteMapping("/delete/{id}")
public Result deletePostTag(@PathVariable Long id) {
logger.info("开始删除帖子标签ID{}", id);
postTagService.deletePostTag(id);
logger.info("帖子标签ID{}删除成功", id);
return Result.ok();
}
/**
* 获取当前帖子所有标签列表接口。
* @return
*/
@GetMapping("/getPostTagList{postId}")
public Result getPostTagList(@PathVariable("postId") Long postId) {
logger.info("开始获取帖子标签列表");
List<Tag> tags = postTagService.getPostTagList(postId);
return Result.ok(tags);
}
/**
* 获取当前标签所有帖子列表接口。
* @return
*/
@GetMapping("/getTagPostList{tagId}")
public Result getTagPostList(@PathVariable("tagId") Long tagId) {
logger.info("开始获取帖子标签列表");
List<Post> posts = postTagService.getTagPostList(tagId);
return Result.ok(posts);
}
}

View File

@@ -0,0 +1,114 @@
package com.ivmiku.tutorial.controller;
import com.ivmiku.tutorial.entity.Tag;
import com.ivmiku.tutorial.response.Result;
import com.ivmiku.tutorial.service.PostTagService;
import com.ivmiku.tutorial.service.TagService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/tag")
public class TagController {
// 日志记录器,用于记录控制器中的日志信息
private static final Logger logger = LoggerFactory.getLogger(TagController.class);
// 通过@Autowired注解自动装配TagService服务
@Autowired
private TagService tagService;
@Autowired
private PostTagService postTagService;
/**
* 创建标签接口。
* 用户通过POST请求提交标签数据服务端接收并保存标签。
*
* @param tag 提交的标签数据
* @return Result 返回操作结果
*/
@PostMapping("/create")
public Result createTag(@RequestBody Tag tag) {
logger.info("开始创建标签:{}", tag.getName());
tagService.createTag(tag);
logger.info("标签创建成功标签ID{}", tag.getTagId());
return Result.ok();
}
/**
* 获取标签详情接口。
* 根据标签ID获取标签的详细信息。
*
* @param id 标签的唯一标识ID
* @return Result 返回操作结果和标签详情
*/
@GetMapping("/get/{id}")
public Result getTag(@PathVariable Long id) {
logger.info("开始获取标签ID{}的详细信息", id);
Tag tag = tagService.getTagById(id);
if (tag != null) {
logger.info("标签ID{}的详细信息获取成功", id);
} else {
logger.warn("未找到ID为{}的标签", id);
}
return Result.ok(tag);
}
/**
* 更新标签接口。
* 用户通过PUT请求提交更新后的标签数据服务端接收并更新标签。
*
* @param id 要更新的标签的唯一标识ID
* @param tag 更新后的标签数据
* @return Result 返回操作结果
*/
@PutMapping("/update/{id}")
public Result updateTag(@PathVariable Long id, @RequestBody Tag tag) {
logger.info("开始更新标签ID{}的信息", id);
tagService.updateTag(id, tag);
logger.info("标签ID{}更新成功", id);
return Result.ok();
}
/**
* 删除标签接口。
* 根据标签ID删除指定的标签。
*
* @param id 要删除的标签的唯一标识ID
* @return Result 返回操作结果
*/
@DeleteMapping("/delete/{id}")
public Result deleteTag(@PathVariable Long id) {
logger.info("开始删除标签ID{}", id);
tagService.deleteTag(id);
logger.info("标签ID{}删除成功", id);
return Result.ok();
}
/**
* 获取所有标签详情接口。
*
* @return Result 返回操作结果和标签详情
*/
@GetMapping("/getTagList")
public Result getTagList() {
List<Tag> tags = tagService.getTagList();
return Result.ok(tags);
}
/**
* 获取排序后的标签列表接口。
* @return Result 返回操作结果和排序后的标签列表
*/
@GetMapping("/sorted-tag-list")
public Result getSortedTagList() {
logger.info("开始获取排序后的标签列表");
List<Tag> tags = postTagService.getSortedTagList();
return Result.ok(tags);
}
}

View File

@@ -0,0 +1,44 @@
package com.ivmiku.tutorial.entity;
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 java.io.Serializable;
import java.util.Date;
import lombok.Data;
/**
* @TableName comment
*/
@TableName(value ="comment")
@Data
public class Comment implements Serializable {
@TableId(type = IdType.AUTO)
private Long commentId;
private String userOpenid;
private Long postId;
private String content;
private Long parentCommentId;
private Integer isDeleted;
private Date createdAt;
private Date updatedAt;
@TableField(exist = false)
private String mentionedUserId; // @功能提到的用户ID
@TableField(exist = false)
private String imageUrls; // 存储图片URL多个URL用分号分隔
@TableField(exist = false)
private String videoUrl; // 存储视频URL
private static final long serialVersionUID = 1L;
}

View File

@@ -0,0 +1,24 @@
package com.ivmiku.tutorial.entity;
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 java.io.Serializable;
import lombok.Data;
/**
* @TableName community
*/
@TableName(value ="community")
@Data
public class Community implements Serializable {
@TableId
private Long communityId;
private String name;
private String description;
private static final long serialVersionUID = 1L;
}

View File

@@ -0,0 +1,26 @@
package com.ivmiku.tutorial.entity;
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 java.io.Serializable;
import lombok.Data;
/**
* @TableName favorite
*/
@TableName(value ="favorite")
@Data
public class Favorite implements Serializable {
@TableId
private Long id;
private String userOpenid;
private Long postId;
private Integer isDeleted;
private static final long serialVersionUID = 1L;
}

View File

@@ -0,0 +1,26 @@
package com.ivmiku.tutorial.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import lombok.Data;
/**
* @TableName like
*/
@TableName(value ="likee")
@Data
public class Likee implements Serializable {
@TableId
private Long id;
private String userOpenid;
private Long postId;
private Long commentId;
private Integer isDeleted;
private static final long serialVersionUID = 1L;
}

View File

@@ -0,0 +1,41 @@
package com.ivmiku.tutorial.entity;
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 java.io.Serializable;
import java.util.Date;
import lombok.Data;
/**
* @TableName post
*/
@TableName(value ="post")
@Data
public class Post implements Serializable {
@TableId
private Long postId;
private String userOpenid;
private Long communityId;
private String title;
private String content;
private String videoUrl; // 新增字段存储视频URL
private String imageUrls; // 新增字段存储图片URL多个URL用分号分隔
private Integer isDeleted;
private Integer isOfficial; // 新增字段,标记是否为官方创建的帖子
private Date createdAt;
private Date updatedAt;
private static final long serialVersionUID = 1L;
}

View File

@@ -0,0 +1,22 @@
package com.ivmiku.tutorial.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import lombok.Data;
/**
* @TableName posttag
*/
@TableName(value ="posttag")
@Data
public class PostTag implements Serializable {
@TableId
private Long postTagId;
private Long postId;
private Long tagId;
private static final long serialVersionUID = 1L;
}

View File

@@ -0,0 +1,25 @@
package com.ivmiku.tutorial.entity;
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 java.io.Serializable;
import lombok.Data;
/**
* @TableName tag
*/
@TableName(value ="tag")
@Data
public class Tag implements Serializable {
@TableId
private Long tagId;
private String name;
// 新增的字段,用于区分标签是否为官方标签
private Integer isOfficial;
private static final long serialVersionUID = 1L;
}

View File

@@ -0,0 +1,14 @@
package com.ivmiku.tutorial.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("User")
public class User {
@TableId
private String openid;
private String nickname;
private String avatarUrl;
}

View File

@@ -0,0 +1,24 @@
package com.ivmiku.tutorial.entity;
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 java.io.Serializable;
import lombok.Data;
/**
* @TableName usercommunity
*/
@TableName(value ="usercommunity")
@Data
public class Usercommunity implements Serializable {
@TableId
private Long userCommunityId;
private String userOpenid;
private Long communityId;
private static final long serialVersionUID = 1L;
}

View File

@@ -0,0 +1,18 @@
package com.ivmiku.tutorial.mapper;
import com.ivmiku.tutorial.entity.Comment;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @author rog
* @description 针对表【comment】的数据库操作Mapper
* @createDate 2024-08-05 14:14:14
* @Entity com.ivmiku.tutorial.entity.Comment
*/
public interface CommentMapper extends BaseMapper<Comment> {
}

View File

@@ -0,0 +1,18 @@
package com.ivmiku.tutorial.mapper;
import com.ivmiku.tutorial.entity.Community;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @author rog
* @description 针对表【community】的数据库操作Mapper
* @createDate 2024-08-05 14:15:04
* @Entity com.ivmiku.tutorial.entity.Community
*/
public interface CommunityMapper extends BaseMapper<Community> {
}

View File

@@ -0,0 +1,18 @@
package com.ivmiku.tutorial.mapper;
import com.ivmiku.tutorial.entity.Favorite;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @author rog
* @description 针对表【favorite】的数据库操作Mapper
* @createDate 2024-08-05 14:20:25
* @Entity com.ivmiku.tutorial.entity.Favorite
*/
public interface FavoriteMapper extends BaseMapper<Favorite> {
}

View File

@@ -0,0 +1,18 @@
package com.ivmiku.tutorial.mapper;
import com.ivmiku.tutorial.entity.Likee;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @author rog
* @description 针对表【like】的数据库操作Mapper
* @createDate 2024-08-05 14:20:52
* @Entity com.ivmiku.tutorial.entity.Like
*/
public interface LikeMapper extends BaseMapper<Likee> {
}

View File

@@ -0,0 +1,24 @@
package com.ivmiku.tutorial.mapper;
import com.ivmiku.tutorial.entity.Post;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* @author rog
* @description 针对表【post】的数据库操作Mapper
* @createDate 2024-08-05 14:15:26
* @Entity com.ivmiku.tutorial.entity.Post
*/
public interface PostMapper extends BaseMapper<Post> {
List<Post> getTagPostList(Long tagId);
}

View File

@@ -0,0 +1,18 @@
package com.ivmiku.tutorial.mapper;
import com.ivmiku.tutorial.entity.Post;
import com.ivmiku.tutorial.entity.PostTag;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import java.util.List;
/**
* @author rog
* @description 针对表【posttag】的数据库操作Mapper
* @createDate 2024-08-05 14:15:42
* @Entity com.ivmiku.tutorial.entity.Posttag
*/
public interface PostTagMapper extends BaseMapper<PostTag> {
}

View File

@@ -0,0 +1,33 @@
package com.ivmiku.tutorial.mapper;
import com.ivmiku.tutorial.entity.Post;
import com.ivmiku.tutorial.entity.Tag;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* @author rog
* @description 针对表【tag】的数据库操作Mapper
* @createDate 2024-08-05 14:15:58
* @Entity com.ivmiku.tutorial.entity.Tag
*/
public interface TagMapper extends BaseMapper<Tag> {
List<Tag> getPostTagList(@Param("postId") Long postId);
// 获取按条件排序的标签列表
@Select("SELECT t.*, COUNT(pt.post_id) AS postCount " +
"FROM tag t " +
"LEFT JOIN posttag pt ON t.tag_id = pt.tag_id " +
"GROUP BY t.tag_id " +
"ORDER BY t.is_official DESC, postCount DESC")
List<Tag> getSortedTagList();
}

View File

@@ -0,0 +1,21 @@
package com.ivmiku.tutorial.mapper;
import com.ivmiku.tutorial.entity.Community;
import com.ivmiku.tutorial.entity.Usercommunity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* @author rog
* @description 针对表【usercommunity】的数据库操作Mapper
* @createDate 2024-08-05 14:53:55
* @Entity com.ivmiku.tutorial.entity.Usercommunity
*/
public interface UsercommunityMapper extends BaseMapper<Usercommunity> {
List<Community> getCommunityList(@Param("user_openid") String userId);
}

View File

@@ -0,0 +1,71 @@
package com.ivmiku.tutorial.service;
import com.ivmiku.tutorial.entity.Comment;
import com.baomidou.mybatisplus.extension.service.IService;
import java.sql.Timestamp;
import java.util.List;
/**
* 评论服务接口,定义评论相关的业务操作方法。
*/
public interface CommentService extends IService<Comment> {
/**
* 保存评论。
* 将评论数据保存到数据库。
*
* @param comment 要保存的评论数据
*/
void createComment(Comment comment);
/**
* 根据ID获取评论详情。
* 从数据库中根据评论ID获取评论的详细信息。
*
* @param commentId 评论的唯一标识ID
* @return Comment 返回查询到的评论对象
*/
Comment getCommentById(Long commentId);
/**
* 更新评论。
* 根据评论ID和用户ID更新评论内容。
*
* @param commentId 要更新的评论的唯一标识ID
* @param userId 更新评论的用户ID
* @param comment 更新后的评论数据
*/
void updateComment(Long commentId, String userId, Comment comment);
/**
* 删除评论。
* 根据评论ID删除指定的评论。
*
* @param commentId 要删除的评论的唯一标识ID
* @param userId 删除评论的用户ID
*/
void deleteComment(Long commentId, String userId);
List<Comment> getPostComments(Long postId);
List<Comment> getCommentReplies(Long commentId);
/**
* 回复评论。
* 用户通过POST请求提交回复数据服务端接收并保存回复。
*
* @param parentCommentId 父评论的ID
* @param postId 帖子的ID
* @param content 回复内容
* @param mentionedUserId (可选)@的用户ID
* @return Result 返回操作结果
*/
void createReply(Long parentCommentId, Long postId, String content, String mentionedUserId);
}

View File

@@ -0,0 +1,49 @@
package com.ivmiku.tutorial.service;
import com.ivmiku.tutorial.entity.Community;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
public interface CommunityService extends IService<Community> {
/**
* 创建社区。
* 根据社区信息创建一个新的社区记录。
*
* @param community 社区信息
*/
void createCommunity(Community community);
/**
* 更新社区信息。
* 根据社区ID更新社区的相关信息。
*
* @param id 社区的唯一标识ID
* @param community 更新后的社区信息
*/
void updateCommunity(Long id, Community community);
/**
* 删除社区。
* 根据社区ID删除指定的社区记录。
*
* @param id 社区的唯一标识ID
*/
void deleteCommunity(Long id);
/**
* 根据社区名称获取社区信息。
*
* @param name 社区名称
* @return 社区信息
*/
List<Community> getByName(String name);
/**
* 获取社区列表。
*
* @return 社区列表
*/
List<Community> getCommunityList();
}

View File

@@ -0,0 +1,14 @@
package com.ivmiku.tutorial.service;
import com.ivmiku.tutorial.response.Result;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.util.UUID;
public interface FileService {
String uploadMinio(MultipartFile file) throws Exception;
Result downLoadMinio(String url, HttpServletResponse response) throws Exception;
}

View File

@@ -0,0 +1,13 @@
package com.ivmiku.tutorial.service;
/**
* InteractionService接口定义用户对帖子和评论的收藏与点赞操作。
*/
public interface InteractionService {
void favoritePost(String userOpenid, Long postId);
void unfavoritePost(String userOpenid, Long postId);
void likePost(String userOpenid, Long postId);
void unlikePost(String userOpenid, Long postId);
void likeComment(String userOpenid, Long commentId);
void unlikeComment(String userOpenid, Long commentId);
}

View File

@@ -0,0 +1,21 @@
package com.ivmiku.tutorial.service;
import com.ivmiku.tutorial.entity.Post;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
public interface PostService extends IService<Post> {
void createPost(Post post);
Post getPostById(Long postId);
void updatePost(Long postId, String userId, Post post);
void deletePost(Long postId, String userId);
List<Post> getPostList(String userId);
List<Post> getCommunityPostList(Long communityId);
List<Post> getOfficialPosts(); // 新增获取官方帖子的方法
List<Post> getNonOfficialPosts(); // 新增获取非官方帖子的方法
}

View File

@@ -0,0 +1,54 @@
package com.ivmiku.tutorial.service;
import com.ivmiku.tutorial.entity.Post;
import com.ivmiku.tutorial.entity.PostTag;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ivmiku.tutorial.entity.Tag;
import java.util.List;
public interface PostTagService extends IService<PostTag> {
/**
* 创建帖子标签。
* 将帖子标签数据保存到数据库。
*
* @param postTag 要保存的帖子标签数据
*/
void createPostTag(PostTag postTag);
/**
* 根据ID获取帖子标签详情。
* 从数据库中根据帖子标签ID获取帖子标签的详细信息。
*
* @param postTagId 帖子标签的唯一标识ID
* @return PostTag 返回查询到的帖子标签对象
*/
PostTag getPostTagById(Long postTagId);
/**
* 更新帖子标签。
* 根据帖子标签ID更新帖子标签的内容。
*
* @param postTagId 要更新的帖子标签的唯一标识ID
* @param postTag 更新后的帖子标签数据
*/
void updatePostTag(Long postTagId, PostTag postTag);
/**
* 删除帖子标签。
* 根据帖子标签ID删除指定的帖子标签。
*
* @param postTagId 要删除的帖子标签的唯一标识ID
*/
void deletePostTag(Long postTagId);
List<Tag> getPostTagList(Long postId);
List<Post> getTagPostList(Long tagId);
List<Tag> getSortedTagList();
}

View File

@@ -0,0 +1,37 @@
package com.ivmiku.tutorial.service;
import com.ivmiku.tutorial.entity.Tag;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
public interface TagService extends IService<Tag> {
/**
* 创建标签
* @param tag 标签实体对象
*/
void createTag(Tag tag);
/**
* 根据ID获取标签
* @param tagId 标签ID
* @return 标签实体对象
*/
Tag getTagById(Long tagId);
/**
* 更新标签信息
* @param tagId 标签ID
* @param tag 更新后的标签实体对象
*/
void updateTag(Long tagId, Tag tag);
/**
* 删除标签
* @param tagId 标签ID
*/
void deleteTag(Long tagId);
List<Tag> getTagList();
}

View File

@@ -0,0 +1,172 @@
package com.ivmiku.tutorial.service.impl;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ivmiku.tutorial.entity.Comment;
import com.ivmiku.tutorial.mapper.CommentMapper;
import com.ivmiku.tutorial.service.CommentService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.sql.Timestamp;
import java.util.List;
/**
* 评论服务实现类。
*/
@Service
public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> implements CommentService {
// 日志记录器,用于记录服务层的日志信息
private static final Logger logger = LoggerFactory.getLogger(CommentServiceImpl.class);
@Autowired
protected CommentMapper commentMapper;
/**
* 保存评论。
* 将评论数据保存到数据库。
*
* @param comment 要保存的评论数据
*/
@Override
public void createComment(Comment comment) {
logger.info("开始保存评论数据");
comment.setCreatedAt(new Timestamp(System.currentTimeMillis()));
comment.setUpdatedAt(new Timestamp(System.currentTimeMillis()));
comment.setIsDeleted(0);
save(comment);
logger.info("评论数据保存成功评论ID{}", comment.getCommentId());
}
/**
* 根据ID获取评论详情。
* 从数据库中根据评论ID获取评论的详细信息。
*
* @param commentId 评论的唯一标识ID
* @return Comment 返回查询到的评论对象
*/
@Override
public Comment getCommentById(Long commentId) {
logger.info("开始根据ID获取评论详情评论ID{}", commentId);
return getById(commentId);
}
/**
* 更新评论。
* 根据评论ID和用户ID更新评论内容。
*
* @param commentId 要更新的评论的唯一标识ID
* @param userId 更新评论的用户ID
* @param comment 更新后的评论数据
*/
@Override
public void updateComment(Long commentId, String userId, Comment comment) {
logger.info("用户ID{}开始更新评论评论ID{}", userId, commentId);
comment.setCommentId(commentId);
comment.setUpdatedAt(new Timestamp(System.currentTimeMillis()));
updateById(comment);
logger.info("用户ID{}的评论ID{}更新成功", userId, commentId);
}
/**
* 删除评论。
* 根据评论ID删除指定的评论。
*
* @param commentId 要删除的评论的唯一标识ID
* @param userId 删除评论的用户ID
*/
@Override
public void deleteComment(Long commentId, String userId) {
logger.info("用户ID{}开始删除评论评论ID{}", userId, commentId);
Comment comment = getById(commentId);
if (comment != null) {
comment.setIsDeleted(1); // 标记为已删除
comment.setUpdatedAt(new Timestamp(System.currentTimeMillis()));
updateById(comment);
logger.info("用户ID{}的评论ID{}删除成功", userId, commentId);
} else {
logger.warn("尝试删除的评论ID{}不存在", commentId);
}
}
/**
* 获取帖子下的所有评论。
*
* @param postId 帖子的唯一标识ID
* @return List<Comment> 返回评论列表
*/
@Override
public List<Comment> getPostComments(Long postId) {
logger.info("开始获取帖子ID{}的评论列表", postId);
LambdaQueryWrapper<Comment> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Comment::getPostId, postId).eq(Comment::getIsDeleted, 0);
List<Comment> comments = commentMapper.selectList(wrapper);
if (comments != null) {
logger.info("获取帖子ID{}的评论列表成功", postId);
} else {
logger.warn("帖子ID{}的评论列表为空", postId);
}
return comments;
}
/**
* 获取评论下的所有回复。
*
* @param commentId 评论的唯一标识ID
* @return List<Comment> 返回回复列表
*/
@Override
public List<Comment> getCommentReplies(Long commentId) {
logger.info("开始获取评论ID{}的回复列表", commentId);
LambdaQueryWrapper<Comment> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Comment::getParentCommentId, commentId).eq(Comment::getIsDeleted, 0);
List<Comment> replies = commentMapper.selectList(wrapper);
if (replies != null) {
logger.info("获取评论ID{}的回复列表成功", commentId);
} else {
logger.warn("评论ID{}的回复列表为空", commentId);
}
return replies;
}
/**
* 回复评论。
* 用户通过POST请求提交回复数据服务端接收并保存回复。
*
* @param parentCommentId 父评论的ID
* @param postId 帖子的ID
* @param content 回复内容
* @param mentionedUserId (可选)@的用户ID
* @return Result 返回操作结果
*/
@Override
public void createReply(Long parentCommentId, Long postId, String content, String mentionedUserId) {
logger.info("回复评论请求开始父评论ID{}帖子ID{}", parentCommentId, postId);
// 检查父评论是否存在
Comment parentComment = getCommentById(parentCommentId);
if (parentComment == null) {
logger.warn("父评论ID{}不存在", parentCommentId);
throw new RuntimeException("父评论不存在");
}
// 创建回复评论对象
Comment reply = new Comment();
reply.setUserOpenid(StpUtil.getLoginIdAsString());
reply.setParentCommentId(parentCommentId);
reply.setPostId(postId);
reply.setContent(content);
if (mentionedUserId != null) {
reply.setMentionedUserId(mentionedUserId);
}
createComment(reply);
logger.info("评论回复成功评论ID{}", reply.getCommentId());
}
}

View File

@@ -0,0 +1,91 @@
package com.ivmiku.tutorial.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ivmiku.tutorial.entity.Community;
import com.ivmiku.tutorial.mapper.CommunityMapper;
import com.ivmiku.tutorial.response.Result;
import com.ivmiku.tutorial.service.CommunityService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 社区服务实现类。
*/
@Service
public class CommunityServiceImpl extends ServiceImpl<CommunityMapper, Community> implements CommunityService {
// 日志记录器,用于记录服务层的日志信息
private static final Logger logger = LoggerFactory.getLogger(CommunityServiceImpl.class);
@Autowired
private CommunityMapper communityMapper;
/**
* 创建社区。
* 根据社区信息创建一个新的社区记录。
*
* @param community 社区信息
*/
@Override
public void createCommunity(Community community) {
logger.info("开始创建社区");
save(community);
logger.info("社区创建成功社区ID{}", community.getCommunityId());
}
/**
* 更新社区信息。
* 根据社区ID更新社区的相关信息。
*
* @param id 社区的唯一标识ID
* @param community 更新后的社区信息
*/
@Override
public void updateCommunity(Long id, Community community) {
logger.info("开始更新社区信息社区ID{}", id);
community.setCommunityId(id);
updateById(community);
logger.info("社区信息更新成功社区ID{}", id);
}
/**
* 删除社区。
* 根据社区ID删除指定的社区记录。
*
* @param id 社区的唯一标识ID
*/
@Override
public void deleteCommunity(Long id) {
logger.info("开始删除社区社区ID{}", id);
removeById(id);
logger.info("社区删除成功社区ID{}", id);
}
/**
* 根据社区名称获取社区信息。
* @param name
* @return
*/
@Override
public List<Community> getByName(String name) {
LambdaQueryWrapper<Community> wrapper = new LambdaQueryWrapper<>();
//根据社区名称模糊查询
wrapper.like(Community::getName, name);
List<Community> communitys = communityMapper.selectList(wrapper);
return communitys;
}
/**
* 获取社区列表
* @return 社区列表
*/
@Override
public List<Community> getCommunityList() {
return communityMapper.selectList(null);
}
}

View File

@@ -0,0 +1,49 @@
package com.ivmiku.tutorial.service.impl;
import com.ivmiku.tutorial.response.Result;
import com.ivmiku.tutorial.service.FileService;
import com.ivmiku.tutorial.util.MinioClientUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.util.UUID;
@Service
public class FileServiceImpl implements FileService {
@Autowired
private MinioClientUtil minioClientUtil;
@Value("${minio.endpoint}")
private String endpoint;
@Value("${minio.port}")
private String port;
@Value("${minio.bucketName}")
private String bucketName;
@Override
public String uploadMinio(MultipartFile file) throws Exception {
String filename = file.getOriginalFilename();
String uuid = UUID.randomUUID().toString();
String imgType = filename.substring(filename.lastIndexOf("."));
String fileName = uuid + imgType;
boolean flag = minioClientUtil.putObject(fileName, file.getInputStream());
String path = "http://" + endpoint + ":" + port + "/" + bucketName + "/" + fileName;
return flag ? path : "上传失败";
}
@Override
public Result downLoadMinio(String url, HttpServletResponse response) throws Exception {
String trim = url.trim();
String path = trim.substring(trim.indexOf("/", 1), trim.length());
minioClientUtil.getObject(path, response);
return Result.ok();
}
}

View File

@@ -0,0 +1,98 @@
package com.ivmiku.tutorial.service.impl;
import com.ivmiku.tutorial.entity.Favorite;
import com.ivmiku.tutorial.entity.Likee;
import com.ivmiku.tutorial.mapper.FavoriteMapper;
import com.ivmiku.tutorial.mapper.LikeMapper;
import com.ivmiku.tutorial.service.InteractionService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* InteractionServiceImpl 实现了 InteractionService 接口,处理用户对帖子和评论的收藏与点赞操作。
*/
@Slf4j
@Service
public class InteractionServiceImpl implements InteractionService {
@Resource
private FavoriteMapper favoriteMapper;
@Resource
private LikeMapper likeMapper;
@Override
public void favoritePost(String userOpenid, Long postId) {
log.info("User {} is favoriting post {}", userOpenid, postId);
Favorite favorite = new Favorite();
favorite.setUserOpenid(userOpenid);
favorite.setPostId(postId);
favorite.setIsDeleted(0);
favoriteMapper.insert(favorite);
}
@Override
public void unfavoritePost(String userOpenid, Long postId) {
log.info("User {} is unfavoriting post {}", userOpenid, postId);
QueryWrapper<Favorite> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("user_openid", userOpenid)
.eq("post_id", postId)
.eq("is_deleted", 0);
Favorite favorite = favoriteMapper.selectOne(queryWrapper);
if (favorite != null) {
favorite.setIsDeleted(1);
favoriteMapper.updateById(favorite);
}
}
@Override
public void likePost(String userOpenid, Long postId) {
log.info("User {} is liking post {}", userOpenid, postId);
Likee likee = new Likee();
likee.setUserOpenid(userOpenid);
likee.setPostId(postId);
likee.setIsDeleted(0);
likeMapper.insert(likee);
}
@Override
public void unlikePost(String userOpenid, Long postId) {
log.info("User {} is unliking post {}", userOpenid, postId);
QueryWrapper<Likee> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("user_openid", userOpenid)
.eq("post_id", postId)
.eq("is_deleted", 0);
Likee likee = likeMapper.selectOne(queryWrapper);
if (likee != null) {
likee.setIsDeleted(1);
likeMapper.updateById(likee);
}
}
@Override
public void likeComment(String userOpenid, Long commentId) {
log.info("User {} is liking comment {}", userOpenid, commentId);
Likee likee = new Likee();
likee.setUserOpenid(userOpenid);
likee.setCommentId(commentId);
likee.setIsDeleted(0);
likeMapper.insert(likee);
}
@Override
public void unlikeComment(String userOpenid, Long commentId) {
log.info("User {} is unliking comment {}", userOpenid, commentId);
QueryWrapper<Likee> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("user_openid", userOpenid)
.eq("comment_id", commentId)
.eq("is_deleted", 0);
Likee likee = likeMapper.selectOne(queryWrapper);
if (likee != null) {
likee.setIsDeleted(1);
likeMapper.updateById(likee);
}
}
}

View File

@@ -0,0 +1,99 @@
package com.ivmiku.tutorial.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ivmiku.tutorial.entity.Post;
import com.ivmiku.tutorial.mapper.PostMapper;
import com.ivmiku.tutorial.service.PostService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.sql.Timestamp;
import java.util.List;
@Service
public class PostServiceImpl extends ServiceImpl<PostMapper, Post> implements PostService {
private static final Logger logger = LoggerFactory.getLogger(PostServiceImpl.class);
@Autowired
private PostMapper postMapper;
@Override
public void createPost(Post post) {
logger.info("开始创建帖子");
post.setCreatedAt(new Timestamp(System.currentTimeMillis())); // 设置创建时间
post.setUpdatedAt(new Timestamp(System.currentTimeMillis())); // 设置更新时间
post.setIsDeleted(0); // 初始化为未删除
save(post);
logger.info("帖子创建成功帖子ID{}", post.getPostId());
}
@Override
public Post getPostById(Long postId) {
logger.info("开始根据ID获取帖子详情帖子ID{}", postId);
return getById(postId);
}
@Override
public void updatePost(Long postId, String userId, Post post) {
logger.info("用户ID{}开始更新帖子帖子ID{}", userId, postId);
post.setPostId(postId);
post.setUpdatedAt(new Timestamp(System.currentTimeMillis())); // 更新修改时间
updateById(post);
logger.info("用户ID{}的帖子ID{}更新成功", userId, postId);
}
@Override
public void deletePost(Long postId, String userId) {
logger.info("用户ID{}开始删除帖子帖子ID{}", userId, postId);
Post post = getById(postId);
if (post != null) {
post.setIsDeleted(1); // 设置为已删除
post.setUpdatedAt(new Timestamp(System.currentTimeMillis())); // 更新修改时间
updateById(post);
logger.info("用户ID{}的帖子ID{}删除成功", userId, postId);
} else {
logger.warn("尝试删除的帖子ID{}不存在", postId);
}
}
@Override
public List<Post> getPostList(String userId) {
logger.info("用户ID{}开始获取帖子列表", userId);
LambdaQueryWrapper<Post> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Post::getUserOpenid, userId);
List<Post> posts = postMapper.selectList(wrapper);
return posts;
}
@Override
public List<Post> getCommunityPostList(Long communityId) {
logger.info("开始获取社区ID{}的帖子列表", communityId);
LambdaQueryWrapper<Post> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Post::getCommunityId, communityId);
List<Post> posts = postMapper.selectList(wrapper);
return posts;
}
@Override
public List<Post> getOfficialPosts() {
logger.info("开始获取所有官方创建的帖子");
LambdaQueryWrapper<Post> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Post::getIsOfficial, 1);
List<Post> posts = postMapper.selectList(wrapper);
return posts;
}
@Override
public List<Post> getNonOfficialPosts() {
logger.info("开始获取所有非官方创建的帖子");
LambdaQueryWrapper<Post> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Post::getIsOfficial, 0);
List<Post> posts = postMapper.selectList(wrapper);
return posts;
}
}

View File

@@ -0,0 +1,107 @@
package com.ivmiku.tutorial.service.impl;
import com.ivmiku.tutorial.entity.Post;
import com.ivmiku.tutorial.entity.PostTag;
import com.ivmiku.tutorial.entity.Tag;
import com.ivmiku.tutorial.mapper.PostMapper;
import com.ivmiku.tutorial.mapper.PostTagMapper;
import com.ivmiku.tutorial.mapper.TagMapper;
import com.ivmiku.tutorial.service.PostTagService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 帖子标签服务实现类。
*/
@Service
public class PostTagServiceImpl extends ServiceImpl<PostTagMapper, PostTag> implements PostTagService {
// 日志记录器,用于记录服务层的日志信息
private static final Logger logger = LoggerFactory.getLogger(PostTagServiceImpl.class);
@Autowired
private TagMapper tagMapper;
@Autowired
private PostMapper postMapper;
@Autowired
private PostTagMapper postTagMapper;
/**
* 创建帖子标签。
* 将帖子标签数据保存到数据库。
*
* @param postTag 要保存的帖子标签数据
*/
@Override
public void createPostTag(PostTag postTag) {
logger.info("开始创建帖子标签");
save(postTag);
logger.info("帖子标签创建成功标签ID{}", postTag.getPostTagId());
}
/**
* 根据ID获取帖子标签详情。
* 从数据库中根据帖子标签ID获取帖子标签的详细信息。
*
* @param postTagId 帖子标签的唯一标识ID
* @return PostTag 返回查询到的帖子标签对象
*/
@Override
public PostTag getPostTagById(Long postTagId) {
logger.info("开始根据ID获取帖子标签详情标签ID{}", postTagId);
return getById(postTagId);
}
/**
* 更新帖子标签。
* 根据帖子标签ID更新帖子标签的内容。
*
* @param postTagId 要更新的帖子标签的唯一标识ID
* @param postTag 更新后的帖子标签数据
*/
@Override
public void updatePostTag(Long postTagId, PostTag postTag) {
logger.info("开始更新帖子标签标签ID{}", postTagId);
postTag.setPostTagId(postTagId);
updateById(postTag);
logger.info("帖子标签更新成功标签ID{}", postTagId);
}
/**
* 删除帖子标签。
* 根据帖子标签ID删除指定的帖子标签。
*
* @param postTagId 要删除的帖子标签的唯一标识ID
*/
@Override
public void deletePostTag(Long postTagId) {
logger.info("开始删除帖子标签标签ID{}", postTagId);
removeById(postTagId);
logger.info("帖子标签删除成功标签ID{}", postTagId);
}
@Override
public List<Tag> getPostTagList(Long postId) {
logger.info("开始获取帖子标签列表帖子ID{}", postId);
return tagMapper.getPostTagList(postId);
}
@Override
public List<Post> getTagPostList(Long tagId) {
logger.info("开始获取标签帖子列表标签ID{}", tagId);
return postMapper.getTagPostList(tagId);
}
@Override
public List<Tag> getSortedTagList() {
logger.info("开始获取排序后的标签列表");
return tagMapper.getSortedTagList();
}
}

View File

@@ -0,0 +1,97 @@
package com.ivmiku.tutorial.service.impl;
import com.ivmiku.tutorial.entity.Tag;
import com.ivmiku.tutorial.mapper.TagMapper;
import com.ivmiku.tutorial.service.TagService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 标签服务实现类
*/
@Service
public class TagServiceImpl extends ServiceImpl<TagMapper, Tag> implements TagService {
// 使用SLF4J的LoggerFactory创建一个Logger实例
private static final Logger logger = LoggerFactory.getLogger(TagServiceImpl.class);
@Autowired
private TagMapper tagMapper;
/**
* 创建标签
* @param tag 标签实体对象
*/
@Override
public void createTag(Tag tag) {
try {
// 保存标签到数据库
save(tag);
logger.info("Tag created successfully: {}", tag);
} catch (Exception e) {
logger.error("Failed to create tag: {}", tag, e);
}
}
/**
* 根据ID获取标签
* @param tagId 标签ID
* @return 标签实体对象
*/
@Override
public Tag getTagById(Long tagId) {
try {
// 根据ID查询标签
return getById(tagId);
} catch (Exception e) {
logger.error("Failed to get tag by id: {}", tagId, e);
return null;
}
}
/**
* 更新标签信息
* @param tagId 标签ID
* @param tag 更新后的标签实体对象
*/
@Override
public void updateTag(Long tagId, Tag tag) {
try {
// 设置标签ID并更新标签信息
tag.setTagId(tagId);
updateById(tag);
logger.info("Tag updated successfully: {}", tag);
} catch (Exception e) {
logger.error("Failed to update tag with id {}: {}", tagId, tag, e);
}
}
/**
* 删除标签
* @param tagId 标签ID
*/
@Override
public void deleteTag(Long tagId) {
try {
// 根据ID删除标签
removeById(tagId);
logger.info("Tag deleted successfully with id: {}", tagId);
} catch (Exception e) {
logger.error("Failed to delete tag with id: {}", tagId, e);
}
}
@Override
public List<Tag> getTagList() {
List<Tag> tags = tagMapper.selectList(null);
if (tags != null) {
return tags;
}
return null;
}
}

View File

@@ -0,0 +1,37 @@
package com.ivmiku.tutorial.util;
import com.ivmiku.tutorial.response.Result;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@RestControllerAdvice
public class BusinessControllerAdvice {
@ExceptionHandler(CustomException.class)
public Result customException(CustomException e) {
return new Result(500, e.getMessage(), null);
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public Result methodArgumentNotValidException(MethodArgumentNotValidException e) {
BindingResult bindingResult = e.getBindingResult();
List<FieldError> fieldErrors = bindingResult.getFieldErrors();
HashMap<Object, Object> allErrors = new HashMap<>();
List<String> errors = new ArrayList<>();
for (FieldError fieldError : fieldErrors) {
allErrors.put(fieldError.getField(), fieldError.getDefaultMessage());
}
return new Result(500, "参数校验失败", allErrors);
}
}

View File

@@ -0,0 +1,13 @@
package com.ivmiku.tutorial.util;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CustomException extends Exception{
String message;
}

View File

@@ -0,0 +1,121 @@
package com.ivmiku.tutorial.util;
import io.minio.MinioClient;
import io.minio.ObjectStat;
import io.minio.PutObjectOptions;
import io.minio.Result;
import io.minio.errors.*;
import io.minio.messages.DeleteError;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
@Component
public class MinioClientUtil {
@Value("${minio.bucketName}")
private String bucketName;
@Resource
private MinioClient minioClient;
private static final int DEFAULT_EXPIRY_TIME = 7 * 24 * 3600;
public boolean bucketExists(String bucketName) {
try {
return minioClient.bucketExists(bucketName);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public boolean putObject(String objectName, InputStream stream) {
try {
if (bucketExists(bucketName)) {
minioClient.putObject(bucketName, objectName, stream, new PutObjectOptions(stream.available(), -1));
ObjectStat statObject = statObject(objectName);
return statObject != null && statObject.length() > 0;
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
public boolean removeObject(String objectName) {
try {
if (bucketExists(bucketName)) {
minioClient.removeObject(bucketName, objectName);
return true;
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
public List<String> removeObject(List<String> objectNames) {
List<String> deleteErrorNames = new ArrayList<>();
try {
if (bucketExists(bucketName)) {
Iterable<Result<DeleteError>> results = minioClient.removeObjects(bucketName, objectNames);
for (Result<DeleteError> result : results) {
DeleteError error = result.get();
deleteErrorNames.add(error.objectName());
}
}
} catch (Exception e) {
e.printStackTrace();
}
return deleteErrorNames;
}
public ObjectStat statObject(String objectName) {
try {
if (bucketExists(bucketName)) {
return minioClient.statObject(bucketName, objectName);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public String getObjectUrl(String objectName) {
try {
if (bucketExists(bucketName)) {
return minioClient.getObjectUrl(bucketName, objectName);
}
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
public void getObject(String filename, HttpServletResponse response) {
try (InputStream in = minioClient.getObject(bucketName, filename);
OutputStream out = response.getOutputStream()) {
response.reset();
response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
response.setContentType("application/octet-stream");
byte[] buffer = new byte[1024];
int length;
while ((length = in.read(buffer)) > 0) {
out.write(buffer, 0, length);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,24 @@
wx.miniapp.configs[0].appid=wx0d4fdb5c7bf3b12b
wx.miniapp.configs[0].secret=989f155fcc3aee616568473faf1b1d3b
spring.data.redis.host=127.0.0.1
spring.data.redis.port=6379
spring.data.redis.database=0
spring.application.name=community
server.port=8073
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/tutorial?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.cloud.nacos.discovery.enabled=true
management.zipkin.tracing.endpoint=http://127.0.0.1:9411/api/v2/spans
management.tracing.sampling.probability=1.0

View File

@@ -0,0 +1,26 @@
wx.miniapp.configs[0].appid=wx0d4fdb5c7bf3b12b
wx.miniapp.configs[0].secret=989f155fcc3aee616568473faf1b1d3b
spring.data.redis.host=localhost
spring.data.redis.port=6379
spring.data.redis.database=0
spring.application.name=community
server.port=8073
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/tutorial?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
dubbo.application.qos-enable=false
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
minio.endpoint=120.26.243.81
minio.port=9000
minio.accessKey=minio_root
minio.secretKey=minio_123456
minio.bucketName=haixia

View File

@@ -0,0 +1 @@
spring.profiles.active=dev

View File

@@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ivmiku.tutorial.mapper.CommentMapper">
<resultMap id="BaseResultMap" type="com.ivmiku.tutorial.entity.Comment">
<id property="commentId" column="comment_id" jdbcType="BIGINT"/>
<result property="userOpenid" column="user_openid" jdbcType="VARCHAR"/>
<result property="postId" column="post_id" jdbcType="BIGINT"/>
<result property="content" column="content" jdbcType="VARCHAR"/>
<result property="parentCommentId" column="parent_comment_id" jdbcType="BIGINT"/>
<result property="isDeleted" column="is_deleted" jdbcType="TINYINT"/>
<result property="createdAt" column="created_at" jdbcType="TIMESTAMP"/>
<result property="updatedAt" column="updated_at" jdbcType="TIMESTAMP"/>
<result property="mentionedUserId" column="mentioned_user_id" jdbcType="VARCHAR"/> <!-- 新增字段 -->
<result column="image_urls" property="imageUrls" />
<result column="video_url" property="videoUrl" />
</resultMap>
<sql id="Base_Column_List">
comment_id, user_openid, post_id, content,
parent_comment_id, is_deleted, created_at, updated_at,
mentioned_user_id, image_urls, video_url
</sql>
<!-- 查询指定帖子的所有评论 -->
<select id="selectCommentsByPostId" resultMap="BaseResultMap">
SELECT
<include refid="Base_Column_List"/>
FROM comment
WHERE post_id = #{postId} AND is_deleted = 0
</select>
<!-- 查询指定评论的所有回复 -->
<select id="selectRepliesByCommentId" resultMap="BaseResultMap">
SELECT
<include refid="Base_Column_List"/>
FROM comment
WHERE parent_comment_id = #{commentId} AND is_deleted = 0
</select>
<!-- 插入新的评论 -->
<insert id="insertComment" parameterType="com.ivmiku.tutorial.entity.Comment">
INSERT INTO comment (
user_openid, post_id, content, parent_comment_id,
is_deleted, created_at, updated_at, mentioned_user_id
) VALUES (
#{userOpenid}, #{postId}, #{content}, #{parentCommentId},
#{isDeleted}, #{createdAt}, #{updatedAt}, #{mentionedUserId}, #{imageUrls}, #{videoUrl}
)
</insert>
<!-- 更新评论 -->
<update id="updateComment" parameterType="com.ivmiku.tutorial.entity.Comment">
UPDATE comment
SET
user_openid = #{userOpenid},
post_id = #{postId},
content = #{content},
parent_comment_id = #{parentCommentId},
is_deleted = #{isDeleted},
created_at = #{createdAt},
updated_at = #{updatedAt},
mentioned_user_id = #{mentionedUserId},
image_urls = #{imageUrls},
video_url = #{videoUrl}
WHERE comment_id = #{commentId}
</update>
<!-- 删除评论实际上是将is_deleted字段设置为1 -->
<update id="deleteComment">
UPDATE comment
SET is_deleted = 1, updated_at = CURRENT_TIMESTAMP
WHERE comment_id = #{commentId}
</update>
</mapper>

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ivmiku.tutorial.mapper.CommunityMapper">
<resultMap id="BaseResultMap" type="com.ivmiku.tutorial.entity.Community">
<id property="communityId" column="community_id" jdbcType="BIGINT"/>
<result property="name" column="name" jdbcType="VARCHAR"/>
<result property="description" column="description" jdbcType="VARCHAR"/>
</resultMap>
<sql id="Base_Column_List">
community_id,name,description
</sql>
</mapper>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ivmiku.tutorial.mapper.FavoriteMapper">
<resultMap id="BaseResultMap" type="com.ivmiku.tutorial.entity.Favorite">
<id property="id" column="id" jdbcType="BIGINT"/>
<result property="userOpenid" column="user_openid" jdbcType="VARCHAR"/>
<result property="postId" column="post_id" jdbcType="BIGINT"/>
<result property="isDeleted" column="is_deleted" jdbcType="TINYINT"/>
</resultMap>
<sql id="Base_Column_List">
id,user_openid,post_id,
is_deleted
</sql>
</mapper>

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ivmiku.tutorial.mapper.LikeMapper">
<resultMap id="BaseResultMap" type="com.ivmiku.tutorial.entity.Likee">
<id property="id" column="id" jdbcType="BIGINT"/>
<result property="userOpenid" column="user_openid" jdbcType="VARCHAR"/>
<result property="postId" column="post_id" jdbcType="BIGINT"/>
<result property="commentId" column="comment_id" jdbcType="BIGINT"/>
<result property="isDeleted" column="is_deleted" jdbcType="TINYINT"/>
</resultMap>
<sql id="Base_Column_List">
id,user_openid,post_id,
comment_id,is_deleted
</sql>
</mapper>

View File

@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ivmiku.tutorial.mapper.PostMapper">
<resultMap id="BaseResultMap" type="com.ivmiku.tutorial.entity.Post">
<id property="postId" column="post_id" jdbcType="BIGINT"/>
<result property="userOpenid" column="user_openid" jdbcType="VARCHAR"/>
<result property="communityId" column="community_id" jdbcType="BIGINT"/>
<result property="title" column="title" jdbcType="VARCHAR"/>
<result property="content" column="content" jdbcType="VARCHAR"/>
<result property="videoUrl" column="video_url" jdbcType="VARCHAR"/> <!-- 新增字段 -->
<result property="imageUrls" column="image_urls" jdbcType="VARCHAR"/> <!-- 新增字段 -->
<result property="isDeleted" column="is_deleted" jdbcType="TINYINT"/>
<result property="isOfficial" column="is_official" jdbcType="TINYINT"/> <!-- 新增字段 -->
<result property="createdAt" column="created_at" jdbcType="TIMESTAMP"/>
<result property="updatedAt" column="updated_at" jdbcType="TIMESTAMP"/>
</resultMap>
<sql id="Base_Column_List">
post_id, user_openid, community_id, title, content,
video_url, image_urls, <!-- 新增字段 -->
is_deleted, is_official, created_at, updated_at
</sql>
<!-- 查询指定帖子的所有评论 -->
<select id="selectCommentsByPostId" resultMap="BaseResultMap">
SELECT
<include refid="Base_Column_List"/>
FROM post
WHERE post_id = #{postId} AND is_deleted = 0
</select>
<!-- 插入新的帖子 -->
<insert id="insertPost" parameterType="com.ivmiku.tutorial.entity.Post">
INSERT INTO post (
post_id, user_openid, community_id, title, content,
video_url, image_urls, <!-- 新增字段 -->
is_deleted, is_official, created_at, updated_at
) VALUES (
#{postId}, #{userOpenid}, #{communityId}, #{title}, #{content},
#{videoUrl}, #{imageUrls}, <!-- 新增字段 -->
#{isDeleted}, #{isOfficial}, #{createdAt}, #{updatedAt}
)
</insert>
<!-- 更新帖子 -->
<update id="updatePost" parameterType="com.ivmiku.tutorial.entity.Post">
UPDATE post
SET
user_openid = #{userOpenid},
community_id = #{communityId},
title = #{title},
content = #{content},
video_url = #{videoUrl}, <!-- 新增字段 -->
image_urls = #{imageUrls}, <!-- 新增字段 -->
is_deleted = #{isDeleted},
is_official = #{isOfficial},
created_at = #{createdAt},
updated_at = #{updatedAt}
WHERE post_id = #{postId}
</update>
<!-- 删除帖子实际上是将is_deleted字段设置为1 -->
<update id="deletePost">
UPDATE post
SET is_deleted = 1, updated_at = CURRENT_TIMESTAMP
WHERE post_id = #{postId}
</update>
<select id="getTagPostList" resultType="com.ivmiku.tutorial.entity.Post">
SELECT p.post_id, p.user_openid, p.community_id, p.title, p.content,
p.is_deleted, p.is_official, p.created_at, p.updated_at
FROM post p, posttag pt, tag t
WHERE p.post_id = pt.post_id AND pt.tag_id = t.tag_id AND t.tag_id = #{tagId} AND p.is_deleted = 0
</select>
</mapper>

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ivmiku.tutorial.mapper.PostTagMapper">
<resultMap id="BaseResultMap" type="com.ivmiku.tutorial.entity.PostTag">
<id property="postTagId" column="post_tag_id" jdbcType="BIGINT"/>
<result property="postId" column="post_id" jdbcType="BIGINT"/>
<result property="tagId" column="tag_id" jdbcType="BIGINT"/>
</resultMap>
<sql id="Base_Column_List">
post_tag_id,post_id,tag_id
</sql>
</mapper>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ivmiku.tutorial.mapper.TagMapper">
<resultMap id="BaseResultMap" type="com.ivmiku.tutorial.entity.Tag">
<id property="tagId" column="tag_id" jdbcType="BIGINT"/>
<result property="name" column="name" jdbcType="VARCHAR"/>
<result property="isOfficial" column="is_official" jdbcType="TINYINT"/>
</resultMap>
<sql id="Base_Column_List">
tag_id,name
</sql>
<select id="getPostTagList" resultType="com.ivmiku.tutorial.entity.Tag">
SELECT t.`name`, t.tag_id, t.is_official
FROM `tag` t, `posttag` pt, `post` p
WHERE t.tag_id = pt.tag_id AND p.post_id = pt.post_id AND pt.post_id = #{postId} AND p.is_deleted = 0
</select>
</mapper>

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ivmiku.tutorial.mapper.UsercommunityMapper">
<resultMap id="BaseResultMap" type="com.ivmiku.tutorial.entity.Usercommunity">
<id property="userCommunityId" column="user_community_id" jdbcType="BIGINT"/>
<result property="userOpenid" column="user_openid" jdbcType="VARCHAR"/>
<result property="communityId" column="community_id" jdbcType="BIGINT"/>
</resultMap>
<sql id="Base_Column_List">
user_community_id,user_openid,community_id
</sql>
<select id="getCommunityList" resultType="com.ivmiku.tutorial.entity.Community">
SELECT c.community_id, c.description, c.name
FROM `community` c, `usercommunity` uc
WHERE uc.community_id = c.community_id AND user_openid = #{user_openid}
</select>
</mapper>

View File

@@ -3,7 +3,9 @@ package com.ivmiku.tutorial;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@SpringBootApplication(exclude = {
org.springframework.boot.actuate.autoconfigure.tracing.zipkin.ZipkinAutoConfiguration.class
})
public class Main8133 {
public static void main(String[] args) {
SpringApplication.run(Main8133.class, args);

View File

@@ -11,26 +11,49 @@ import org.springframework.context.annotation.Configuration;
* [Sa-Token 权限认证] 配置类
* @author click33
*/
//@Configuration
//public class SaTokenConfigure {
// // 注册 Sa-Token全局过滤器
// @Bean
// public SaReactorFilter getSaReactorFilter() {
// return new SaReactorFilter()
// // 拦截地址
// .addInclude("/**") /* 拦截全部path */
// // 开放地址
// .addExclude("/favicon.ico")
// // 鉴权方法:每次访问进入
// .setAuth(obj -> {
// // 登录校验 -- 拦截所有路由,并排除/user/doLogin 用于开放登录
// SaRouter.match("/**", "/user/**", r -> StpUtil.checkLogin());
// })
// // 异常处理方法每次setAuth函数出现异常时进入
// .setError(e -> {
// return SaResult.error(e.getMessage());
// });
// }
//}
@Configuration
public class SaTokenConfigure {
// 注册 Sa-Token 全局过滤器
@Bean
public SaReactorFilter getSaReactorFilter() {
return new SaReactorFilter()
// 拦截地址
.addInclude("/**") /* 拦截全部path */
.addInclude("/**") /* 拦截全部路径 */
// 开放地址
.addExclude("/favicon.ico")
.addExclude("/favicon.ico",
"/user/login",
"/user/register",
"/swagger-resources/**",
"/v3/**",
"/swagger-ui/**")
// 鉴权方法:每次访问进入
.setAuth(obj -> {
// 登录校验 -- 拦截所有路由,并排除/user/doLogin 用于开放登录
// 登录校验 -- 拦截所有路由,并排除指定路由
SaRouter.match("/**", "/user/**", r -> StpUtil.checkLogin());
})
// 异常处理方法:每次 setAuth 函数出现异常时进入
.setError(e -> {
return SaResult.error(e.getMessage());
})
;
.setError(e -> SaResult.error(e.getMessage()));
}
}

View File

@@ -1,16 +1,16 @@
server.port=8133
spring.application.name=gateway
spring.cloud.nacos.discovery.server-addr=nacos:8848
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.data.redis.host=redis
spring.data.redis.host=127.0.0.1
spring.data.redis.port=6379
spring.data.redis.database=0
spring.data.redis.password=Shuodedaoli114514
#spring.data.redis.password=Shuodedaoli114514
spring.cloud.gateway.routes[0].id=user
spring.cloud.gateway.routes[0].uri=lb://user
spring.cloud.gateway.routes[0].predicates[0]=Path=/user/**
management.zipkin.tracing.endpoint=http://zipkin:9411/api/v2/spans
management.zipkin.tracing.endpoint=http://127.0.0.1:9411/api/v2/spans
management.tracing.sampling.probability=1.0

View File

@@ -10,6 +10,12 @@ spring.data.redis.database=0
spring.cloud.gateway.routes[0].id=user
spring.cloud.gateway.routes[0].uri=lb://user
spring.cloud.gateway.routes[0].predicates[0]=Path=/user/**
spring.cloud.gateway.routes[0].filters[0]=StripPrefix=1
management.zipkin.tracing.endpoint=http://localhost:9411/api/v2/spans
management.tracing.sampling.probability=1.0
spring.cloud.gateway.routes[1].id=community
spring.cloud.gateway.routes[1].uri=lb://community
spring.cloud.gateway.routes[1].predicates[0]=Path=/community/**
spring.cloud.gateway.routes[1].filters[0]=StripPrefix=1
#management.zipkin.tracing.endpoint=http://localhost:9411/api/v2/spans
#management.tracing.sampling.probability=1.0

View File

@@ -1 +1 @@
spring.profiles.active=dep
spring.profiles.active=dev

102
navigate-8432/pom.xml Normal file
View File

@@ -0,0 +1,102 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.ivmiku.tutorial</groupId>
<artifactId>first-tutorial</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>navigate-8432</artifactId>
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<!-- Sa-Token 权限认证在线文档https://sa-token.cc -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot3-starter</artifactId>
</dependency>
<!-- fastjson2 -->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
</dependency>
<!-- Sa-Token 整合 Redis (使用 jackson 序列化方式) -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-redis-jackson</artifactId>
<version>1.38.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!-- dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.dubbo/dubbo-registry-nacos -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>com.ivmiku.tutorial</groupId>
<artifactId>commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- https://mvnrepository.com/artifact/cn.hutool/hutool-http -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-http</artifactId>
<version>5.8.29</version>
</dependency>
<dependency>
<groupId>com.tencentcloudapi</groupId>
<artifactId>tencentcloud-sdk-java-ocr</artifactId>
<version>3.1.1076</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,13 @@
package com.ivmiku.tutorial;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.ivmiku.tutorial.mapper")
public class Main8432 {
public static void main(String[] args) {
SpringApplication.run(Main8432.class, args);
}
}

View File

@@ -0,0 +1,62 @@
package com.ivmiku.tutorial.controller;
import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.fastjson2.JSON;
import com.ivmiku.tutorial.entity.RouteStep;
import com.ivmiku.tutorial.response.Result;
import com.ivmiku.tutorial.service.NavigateService;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@RestController
@RequestMapping("/navigate")
@SaCheckLogin
public class NavigateController {
@Resource
private NavigateService navigateService;
private static final ConcurrentHashMap<String, List<RouteStep>> STEPS_MAP = new ConcurrentHashMap<>();
@GetMapping("/route")
public Object getRoute(@RequestParam(defaultValue = "") String origin,
@RequestParam(defaultValue = "") String destination,
@RequestParam(defaultValue = "-1") int step) {
String userId = (String) StpUtil.getLoginId();
if (!origin.isEmpty() && !destination.isEmpty()) {
Map<String, Object> route = navigateService.getRoute(origin, destination);
List<RouteStep> stepsList = (List<RouteStep>) route.get("steps");
STEPS_MAP.put(userId, stepsList);
Map<String, Object> map = new HashMap<>();
map.put("total", stepsList.size());
map.put("distance", Integer.parseInt((String) route.get("distance")));
map.put("duration", Integer.parseInt((String) route.get("duration")));
map.put("step", stepsList.getFirst());
return JSON.toJSON(Result.ok(map));
} else if (step >0) {
if (!STEPS_MAP.containsKey(userId)) {
return JSON.toJSON(Result.error("请先获取路线!"));
}
Map<String, Object> map = new HashMap<>();
map.put("step", STEPS_MAP.get(userId).get(step-1));
return JSON.toJSON(Result.ok(map));
}
return JSON.toJSON(Result.error("非法的请求参数"));
}
@PostMapping("/ticket")
public Object scanTicket(@RequestPart MultipartFile file) throws IOException {
BufferedImage image = ImageIO.read(file.getInputStream());
Map<String, Object> map = navigateService.scanTicket(image);
return JSON.toJSON(Result.ok(map));
}
}

View File

@@ -0,0 +1,16 @@
package com.ivmiku.tutorial.entity;
import lombok.Data;
@Data
public class RouteStep {
private String instruction;
private String orientation;
private String road;
private Integer distance;
private Integer duration;
private String polyline;
private String action;
private String assistant_action;
private Integer walk_type;
}

View File

@@ -0,0 +1,84 @@
package com.ivmiku.tutorial.service;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.ivmiku.tutorial.entity.RouteStep;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.ocr.v20181119.OcrClient;
import com.tencentcloudapi.ocr.v20181119.models.*;
import org.springframework.stereotype.Service;
import java.awt.image.BufferedImage;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class NavigateService {
private final String key = "d3aa1b75aff468a5ca5384d2b4b6bfef";
private final String secretId = "AKID09INNYxYEFFJH3g9VhljVF3qbDiFdx50";
private final String secretKey = "KajjcNyNaaUCqQroqpzNoMtTHNj4Lbil";
public Map<String, Object> getRoute(String origin, String destination) {
Map<String, Object> params = new HashMap<>();
params.put("key", key);
params.put("origin", origin);
params.put("destination", destination);
HttpResponse response = HttpRequest.get("https://restapi.amap.com/v3/direction/walking")
.form(params)
.execute();
String result = response.body();
response.close();
JSONObject route = JSONObject.parseObject(JSONObject.parseObject(result).getString("route"));
JSONArray paths = JSONArray.parseArray(route.getString("paths"));
JSONObject path = paths.getJSONObject(0);
String distance = path.getString("distance");
String duration = path.getString("duration");
Map<String, Object> map = new HashMap<>();
map.put("distance", distance);
map.put("duration", duration);
map.put("steps", JSONArray.parseArray(path.getString("steps"), RouteStep.class));
return map;
}
public Map<String, Object> scanTicket(BufferedImage image) {
String base64Img = ImgUtil.toBase64(image, "jpg");
SmartStructuralOCRV2Response resp;
try {
Credential cred = new Credential(secretId, secretKey);
HttpProfile httpProfile = new HttpProfile();
httpProfile.setEndpoint("ocr.tencentcloudapi.com");
ClientProfile clientProfile = new ClientProfile();
clientProfile.setHttpProfile(httpProfile);
OcrClient client = new OcrClient(cred, "ap-shanghai", clientProfile);
SmartStructuralOCRV2Request req = new SmartStructuralOCRV2Request();
req.setImageBase64(base64Img);
String[] itemNames1 = {"登机口", "检票口"};
req.setItemNames(itemNames1);
resp = client.SmartStructuralOCRV2(req);
} catch (TencentCloudSDKException e) {
throw new RuntimeException(e.getMessage());
}
Map<String, Object> result = new HashMap<>();
List<GroupInfo> groupInfoList = Arrays.stream(resp.getStructuralList()).toList();
for (GroupInfo groupInfo : groupInfoList) {
List<LineInfo> lineList = Arrays.stream(groupInfo.getGroups()).toList();
for (LineInfo lineInfo : lineList) {
List<ItemInfo> itemList = Arrays.stream(lineInfo.getLines()).toList();
for (ItemInfo info : itemList) {
if (info.getKey() != null && info.getValue() != null) {
result.put(String.valueOf(info.getKey().getAutoName()), info.getValue().getAutoContent());
}
}
}
}
return result;
}
}

View File

@@ -0,0 +1,61 @@
package com.ivmiku.tutorial.utils;
import cn.dev33.satoken.exception.SaTokenException;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.fastjson2.JSON;
import com.ivmiku.tutorial.response.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import java.sql.SQLException;
import java.text.ParseException;
/**
* @author Aurora
*/
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(value = SaTokenException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ResponseBody
public Object SaTokenExceptionHandler(SaTokenException e) {
log.error("SaTokenException:" + e.getLocalizedMessage());
return JSON.toJSON(Result.error("身份认证错误:" + e.getMessage()));
}
@ExceptionHandler(value = ParseException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ResponseBody
public Object parseExceptionHandler(ParseException e) {
log.error("ParseException:" + e.getLocalizedMessage());
return JSON.toJSON(Result.error("请检查日期是否合法"));
}
@ExceptionHandler(value = SQLException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ResponseBody
public Object SQLExceptionHandler(SQLException e) {
log.error("SQLException:" + e.getLocalizedMessage());
return JSON.toJSON(Result.error("数据库出错!(内部错误)\n" + e.getMessage()));
}
@ExceptionHandler(value = BlockException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ResponseBody
public Object sentinelHandler(BlockException e) {
return JSON.toJSON(Result.error("系统繁忙,请稍后再试"));
}
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Object exceptionHandler(Exception e) {
log.error("Exception:" + e.getLocalizedMessage());
return JSON.toJSON(Result.error("服务器内部错误:" + e.getClass() + ":" + e.getMessage()));
}
}

View File

@@ -0,0 +1,19 @@
spring.data.redis.host=redis
spring.data.redis.port=6379
spring.data.redis.database=0
spring.data.redis.password=Shuodedaoli114514
spring.application.name=navigate
server.port=8432
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=Shuodedaoli114514
spring.datasource.url=jdbc:mysql://mysql:4514/tutorial?useUnicode=true&characterEncoding=utf8&useSSL=false&ServerTimezone=Asia/Shanghai
spring.cloud.nacos.discovery.server-addr=nacos:8848
spring.cloud.nacos.discovery.enabled=true
management.zipkin.tracing.endpoint=http://zipkin:9411/api/v2/spans
management.tracing.sampling.probability=1.0

View File

@@ -0,0 +1,14 @@
spring.data.redis.host=localhost
spring.data.redis.port=6379
spring.data.redis.database=0
spring.application.name=navigate
server.port=8432
dubbo.application.qos-enable=false
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=12345abcde
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/tutorial?useUnicode=true&characterEncoding=utf8&useSSL=false&ServerTimezone=Asia/Shanghai

View File

@@ -0,0 +1 @@
spring.profiles.active=dev

79
pom.xml
View File

@@ -12,6 +12,8 @@
<module>gateway-8133</module>
<module>user-8072</module>
<module>commons</module>
<module>community-8073</module>
</modules>
<properties>
@@ -24,7 +26,7 @@
<hutool.version>5.8.22</hutool.version>
<lombok.version>1.18.30</lombok.version>
<mybatis.springboot.version>3.5.6</mybatis.springboot.version>
<mysql.version>8.0.11</mysql.version>
<mysql.version>8.0.28</mysql.version>
<mapper.version>4.2.3</mapper.version>
<fastjson2.version>2.0.40</fastjson2.version>
<persistence-api.version>1.0.2</persistence-api.version>
@@ -52,6 +54,37 @@
<dependencyManagement>
<dependencies>
<!--Mysql数据库驱动8 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<!--persistence-->
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
<version>1.0.2</version>
</dependency>
<!--hutool-->
<!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.21</version>
</dependency>
<!-- spring-boot-starter-test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>3.1.5</version>
</dependency>
<!--feign-micrometer 5-->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-micrometer</artifactId>
<version>12.5</version>
</dependency>
<!--springboot 3.2.0-->
<dependency>
<groupId>org.springframework.boot</groupId>
@@ -82,30 +115,21 @@
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>${mybatis.springboot.version}</version>
</dependency>
<!--Mysql数据库驱动8 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!--persistence-->
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
<version>${persistence-api.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<!-- <dependency>-->
<!-- <groupId>mysql</groupId>-->
<!-- <artifactId>mysql-connector-java</artifactId>-->
<!-- <version>8.0.30</version>-->
<!-- </dependency>-->
<!-- fastjson2 -->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>${fastjson2.version}</version>
</dependency>
<!--hutool-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
@@ -113,13 +137,7 @@
<version>${lombok.version}</version>
<optional>true</optional>
</dependency>
<!-- spring-boot-starter-test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${spring.boot.test.version}</version>
<scope>test</scope>
</dependency>
<!--micrometer-tracing-bom导入链路追踪版本中心 1-->
<dependency>
@@ -147,12 +165,7 @@
<artifactId>micrometer-observation</artifactId>
<version>${micrometer-observation.version}</version>
</dependency>
<!--feign-micrometer 5-->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-micrometer</artifactId>
<version>${feign-micrometer.version}</version>
</dependency>
<!--zipkin-reporter-brave 6-->
<dependency>
<groupId>io.zipkin.reporter2</groupId>
@@ -184,6 +197,8 @@
<artifactId>weixin-java-miniapp</artifactId>
<version>${wx.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>

View File

@@ -4,7 +4,9 @@ import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@SpringBootApplication(exclude = {
org.springframework.boot.actuate.autoconfigure.tracing.zipkin.ZipkinAutoConfiguration.class
})
@MapperScan("com.ivmiku.tutorial.mapper")
public class Main8072 {
public static void main(String[] args) {

View File

@@ -0,0 +1,41 @@
package com.ivmiku.tutorial.controller;
import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.fastjson2.JSON;
import com.ivmiku.tutorial.response.Result;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping("/login1")
public Object getToken1() {
StpUtil.login("1");
String token = StpUtil.getTokenValue();
HashMap<String, Object> map = new HashMap<>();
map.put("token", token);
return JSON.toJSON(Result.ok(map));
}
@GetMapping("/login2")
public Object getToken2() {
StpUtil.login("2");
String token = StpUtil.getTokenValue();
HashMap<String, Object> map = new HashMap<>();
map.put("token", token);
return JSON.toJSON(Result.ok(map));
}
@PostMapping("test")
public Object test() {
//添加请求头"satoken"值为上方接口返回的token后可以获取token对应的用户id
String userId = (String) StpUtil.getLoginId();
//其他业务逻辑
return Result.ok();
}
}

View File

@@ -1,7 +1,7 @@
wx.miniapp.configs[0].appid=wx0d4fdb5c7bf3b12b
wx.miniapp.configs[0].secret=989f155fcc3aee616568473faf1b1d3b
spring.data.redis.host=redis
spring.data.redis.host=127.0.0.1
spring.data.redis.port=6379
spring.data.redis.database=0
@@ -11,11 +11,11 @@ server.port=8072
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=Shuodedaoli114514
spring.datasource.url=jdbc:mysql://mysql:4514/tutorial?useUnicode=true&characterEncoding=utf8&useSSL=false&ServerTimezone=Asia/Shanghai
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/tutorial?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
spring.cloud.nacos.discovery.server-addr=nacos:8848
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.cloud.nacos.discovery.enabled=true
management.zipkin.tracing.endpoint=http://zipkin:9411/api/v2/spans
management.zipkin.tracing.endpoint=http://127.0.0.1:9411/api/v2/spans
management.tracing.sampling.probability=1.0

View File

@@ -11,5 +11,8 @@ server.port=8072
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=12345abcde
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/tutorial?useUnicode=true&characterEncoding=utf8&useSSL=false&ServerTimezone=Asia/Shanghai
dubbo.application.qos-enable=false

View File

@@ -1 +1 @@
spring.profiles.active=dep
spring.profiles.active=dev