Compare commits

..

4 Commits

114 changed files with 321 additions and 3714 deletions

View File

@@ -39,26 +39,6 @@
<option name="modulePath" value="$PROJECT_DIR$/community-8073" /> <option name="modulePath" value="$PROJECT_DIR$/community-8073" />
<option name="packageName" value="mapper" /> <option name="packageName" value="mapper" />
</ModuleInfoGo> </ModuleInfoGo>
<ModuleInfoGo>
<option name="basePath" value="${domain.basePath}" />
<option name="configFileName" value="serviceImpl.ftl" />
<option name="configName" value="serviceImpl" />
<option name="encoding" value="${domain.encoding}" />
<option name="fileName" value="${domain.fileName}ServiceImpl" />
<option name="fileNameWithSuffix" value="${domain.fileName}ServiceImpl.java" />
<option name="modulePath" value="$PROJECT_DIR$/community-8073" />
<option name="packageName" value="${domain.basePackage}.service.impl" />
</ModuleInfoGo>
<ModuleInfoGo>
<option name="basePath" value="${domain.basePath}" />
<option name="configFileName" value="serviceInterface.ftl" />
<option name="configName" value="serviceInterface" />
<option name="encoding" value="${domain.encoding}" />
<option name="fileName" value="${domain.fileName}Service" />
<option name="fileNameWithSuffix" value="${domain.fileName}Service.java" />
<option name="modulePath" value="$PROJECT_DIR$/community-8073" />
<option name="packageName" value="${domain.basePackage}.service" />
</ModuleInfoGo>
</list> </list>
</option> </option>
<option name="needsModel" value="true" /> <option name="needsModel" value="true" />
@@ -67,8 +47,8 @@
<option name="tableUIInfoList"> <option name="tableUIInfoList">
<list> <list>
<TableUIInfo> <TableUIInfo>
<option name="className" value="TutorialTags" /> <option name="className" value="Usercommunity" />
<option name="tableName" value="tutorial_tags" /> <option name="tableName" value="usercommunity" />
</TableUIInfo> </TableUIInfo>
</list> </list>
</option> </option>

View File

@@ -1,14 +0,0 @@
package com.ivmiku.tutorial.response;
import lombok.Data;
/**
* 提醒用户实体
* @author Aurora
*/
@Data
public class AtNotifier {
private String fromId;
private String toId;
private String postId;
}

View File

@@ -41,12 +41,11 @@
<artifactId>spring-boot-starter-data-redis</artifactId> <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency> </dependency>
<!-- Sa-Token 权限认证在线文档https://sa-token.cc -->
<dependency> <dependency>
<groupId>cn.dev33</groupId> <groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot3-starter</artifactId> <artifactId>sa-token-spring-boot-starter</artifactId>
<version>1.28.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.minio</groupId> <groupId>io.minio</groupId>
<artifactId>minio</artifactId> <artifactId>minio</artifactId>
@@ -133,6 +132,7 @@
<dependency> <dependency>
<groupId>cn.dev33</groupId> <groupId>cn.dev33</groupId>
<artifactId>sa-token-redis-jackson</artifactId> <artifactId>sa-token-redis-jackson</artifactId>
<version>1.38.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.commons</groupId> <groupId>org.apache.commons</groupId>
@@ -190,14 +190,6 @@
<artifactId>commons</artifactId> <artifactId>commons</artifactId>
<version>1.0-SNAPSHOT</version> <version>1.0-SNAPSHOT</version>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

@@ -1,15 +0,0 @@
package com.ivmiku.tutorial.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MpConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}

View File

@@ -1,7 +1,6 @@
package com.ivmiku.tutorial.config; package com.ivmiku.tutorial.config;
import cn.dev33.satoken.interceptor.SaInterceptor; import cn.dev33.satoken.interceptor.SaAnnotationInterceptor;
import cn.dev33.satoken.stp.StpUtil;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@@ -12,8 +11,7 @@ public class SaTokenConfig implements WebMvcConfigurer {
@Override @Override
public void addInterceptors(InterceptorRegistry registry) { public void addInterceptors(InterceptorRegistry registry) {
// 注册注解拦截器,并排除不需要注解鉴权的接口地址 (与登录拦截器无关) // 注册注解拦截器,并排除不需要注解鉴权的接口地址 (与登录拦截器无关)
registry.addInterceptor(new SaInterceptor(handle -> StpUtil.checkLogin())) registry.addInterceptor(new SaAnnotationInterceptor())
.addPathPatterns("/**") .addPathPatterns("/**");
.excludePathPatterns("/swagger-ui/**");
} }
} }

View File

@@ -1,34 +0,0 @@
package com.ivmiku.tutorial.config;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
import org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean;
import org.springframework.web.util.WebAppRootListener;
@Configuration
public class WebSocketConfig implements ServletContextInitializer {
@Bean
public ServerEndpointExporter serverEndpointExporter (){
return new ServerEndpointExporter();
}
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
servletContext.addListener(WebAppRootListener.class);
servletContext.setInitParameter("org.apache.tomcat.websocket.textBufferSize","102400000");
}
@Bean
public ServletServerContainerFactoryBean createWebSocketContainer() {
ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
// 在此处设置bufferSize
container.setMaxTextMessageBufferSize(50*1024*1024);
container.setMaxBinaryMessageBufferSize(50*1024*1024);
container.setMaxSessionIdleTimeout(15 * 60000L);
return container;
}
}

View File

@@ -2,23 +2,20 @@ package com.ivmiku.tutorial.controller;
import cn.dev33.satoken.annotation.SaCheckLogin; import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.fastjson.JSON; import com.github.pagehelper.PageInfo;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.ivmiku.tutorial.entity.Comment; import com.ivmiku.tutorial.entity.Comment;
import com.ivmiku.tutorial.entity.Pages; import com.ivmiku.tutorial.entity.Pages;
import com.ivmiku.tutorial.response.AtNotifier;
import com.ivmiku.tutorial.response.Result; import com.ivmiku.tutorial.response.Result;
import com.ivmiku.tutorial.service.CommentService; import com.ivmiku.tutorial.service.CommentService;
import com.ivmiku.tutorial.service.FileService; import com.ivmiku.tutorial.service.FileService;
import com.ivmiku.tutorial.util.MyRedisUtil;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.List;
/** /**
* 评论控制器用于处理评论相关的HTTP请求。 * 评论控制器用于处理评论相关的HTTP请求。
@@ -26,7 +23,6 @@ import javax.annotation.Resource;
@RestController @RestController
@RequestMapping("/comments") @RequestMapping("/comments")
@SaCheckLogin @SaCheckLogin
public class CommentController { public class CommentController {
private static final Logger logger = LoggerFactory.getLogger(CommentController.class); private static final Logger logger = LoggerFactory.getLogger(CommentController.class);
@@ -37,36 +33,48 @@ public class CommentController {
@Resource @Resource
private FileService fileService; private FileService fileService;
@Resource
private RabbitTemplate rabbitTemplate;
@Resource
private MyRedisUtil myRedisUtil;
/** /**
* 创建评论接口。 * 创建评论接口。
*
* @param content 评论内容
* @param postId 帖子的ID
* @param mentionedUserId 提及的用户ID可选
* @param imageFiles 图片文件(可选)
* @param videoFile 视频文件(可选)
* @return 返回操作结果
*/ */
@PostMapping("/create") @PostMapping("/create")
@Operation(summary = "创建评论") @Operation(summary = "创建评论")
public Result createComment(@RequestParam("content") String content, public Result createComment(@RequestParam("content") String content,
@RequestParam(value = "postId", required = false) Long postId, @RequestParam("postId") Long postId,
@RequestParam(value = "tutorialId", required = false) Long tutorialId,
@RequestParam(value = "mentionedUserId", required = false) String mentionedUserId, @RequestParam(value = "mentionedUserId", required = false) String mentionedUserId,
@RequestParam(value = "imageFiles", required = false) MultipartFile[] imageFiles, @RequestParam(value = "imageFiles", required = false) MultipartFile[] imageFiles,
@RequestParam(value = "videoFile", required = false) MultipartFile videoFile, @RequestParam(value = "videoFile", required = false) MultipartFile videoFile) {
@RequestParam("type") String type) {
logger.info("创建评论请求开始用户ID{}", StpUtil.getLoginIdAsString()); logger.info("创建评论请求开始用户ID{}", StpUtil.getLoginIdAsString());
if (!isValidCommentType(type)) { Comment comment = new Comment();
return Result.error("无效的评论类型"); comment.setUserOpenid(StpUtil.getLoginIdAsString());
} comment.setPostId(postId);
comment.setContent(content);
Comment comment = createCommentObject(content, postId, tutorialId, mentionedUserId, type); comment.setParentCommentId(0l);
comment.setMentionedUserId(mentionedUserId);
try { try {
processFileUploads(comment, imageFiles, videoFile); // 上传视频
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) { } catch (Exception e) {
logger.error("文件上传失败", e); logger.error("文件上传失败", e);
return Result.error("文件上传失败"); return Result.error("文件上传失败");
@@ -74,47 +82,60 @@ public class CommentController {
commentService.createComment(comment); commentService.createComment(comment);
logger.info("评论创建成功评论ID{}", comment.getCommentId()); logger.info("评论创建成功评论ID{}", comment.getCommentId());
if (!mentionedUserId.isEmpty()) {
AtNotifier notifier = new AtNotifier();
notifier.setFromId(comment.getUserOpenid());
notifier.setToId(mentionedUserId);
notifier.setPostId(String.valueOf(comment.getCommentId()));
rabbitTemplate.convertAndSend("exchange2", "", JSON.toJSONString(notifier));
myRedisUtil.listAdd("at:" + notifier.getToId(), JSON.toJSONString(notifier));
}
return Result.ok(comment); return Result.ok(comment);
} }
/** /**
* 回复评论接口。 * 回复评论接口。
*
* @param parentCommentId 父评论的ID
* @param postId 帖子的ID
* @param content 回复内容
* @param mentionedUserId 提及的用户ID可选
* @param imageFiles 图片文件(可选)
* @param videoFile 视频文件(可选)
* @return 返回操作结果
*/ */
@PostMapping("/reply") @PostMapping("/reply")
@Operation(summary = "回复评论") @Operation(summary = "回复评论")
public Result replyComment(@RequestParam Long parentCommentId, public Result replyComment(@RequestParam Long parentCommentId,
@RequestParam("content") String content, @RequestParam Long postId,
@RequestParam(value = "postId", required = false) Long postId, @RequestParam String content,
@RequestParam(value = "tutorialId", required = false) Long tutorialId, @RequestParam(required = false) String mentionedUserId,
@RequestParam(value = "mentionedUserId", required = false) String mentionedUserId,
@RequestParam(value = "imageFiles", required = false) MultipartFile[] imageFiles, @RequestParam(value = "imageFiles", required = false) MultipartFile[] imageFiles,
@RequestParam(value = "videoFile", required = false) MultipartFile videoFile, @RequestParam(value = "videoFile", required = false) MultipartFile videoFile) {
@RequestParam("type") String type) {
logger.info("回复评论请求开始用户ID{}", StpUtil.getLoginIdAsString()); logger.info("回复评论请求开始用户ID{}", StpUtil.getLoginIdAsString());
// 检查父评论是否存在
Comment parentComment = commentService.getCommentById(parentCommentId); Comment parentComment = commentService.getCommentById(parentCommentId);
if (parentComment == null) { if (parentComment == null) {
logger.warn("父评论ID{}不存在", parentCommentId);
return Result.error("父评论不存在"); return Result.error("父评论不存在");
} }
if (!isValidCommentType(type)) { Comment reply = new Comment();
return Result.error("无效的评论类型"); reply.setUserOpenid(StpUtil.getLoginIdAsString());
}
Comment reply = createCommentObject(content, postId, tutorialId, mentionedUserId, type);
reply.setParentCommentId(parentCommentId); reply.setParentCommentId(parentCommentId);
reply.setPostId(postId);
reply.setContent(content);
reply.setMentionedUserId(mentionedUserId);
try { try {
processFileUploads(reply, imageFiles, videoFile); // 上传视频
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) { } catch (Exception e) {
logger.error("文件上传失败", e); logger.error("文件上传失败", e);
return Result.error("文件上传失败"); return Result.error("文件上传失败");
@@ -122,51 +143,9 @@ public class CommentController {
commentService.createComment(reply); commentService.createComment(reply);
logger.info("评论回复成功评论ID{}", reply.getCommentId()); logger.info("评论回复成功评论ID{}", reply.getCommentId());
if (!mentionedUserId.isEmpty()) {
AtNotifier notifier = new AtNotifier();
notifier.setFromId(reply.getUserOpenid());
notifier.setToId(mentionedUserId);
notifier.setPostId(String.valueOf(reply.getCommentId()));
rabbitTemplate.convertAndSend("exchange2", "", JSON.toJSONString(notifier));
myRedisUtil.listAdd("at:" + notifier.getToId(), JSON.toJSONString(notifier));
}
return Result.ok(reply); return Result.ok(reply);
} }
// 工具方法:创建评论对象
private Comment createCommentObject(String content, Long postId, Long tutorialId, String mentionedUserId, String type) {
Comment comment = new Comment();
comment.setUserOpenid(StpUtil.getLoginIdAsString());
comment.setContent(content);
comment.setMentionedUserId(mentionedUserId);
if ("post".equals(type)) {
comment.setPostId(postId);
} else if ("tutorial".equals(type)) {
comment.setTutorialId(tutorialId);
}
return comment;
}
// 工具方法:处理文件上传
private void processFileUploads(Comment comment, MultipartFile[] imageFiles, MultipartFile videoFile) throws Exception {
if (videoFile != null && !videoFile.isEmpty()) {
comment.setVideoUrl(fileService.uploadMinio(videoFile));
}
if (imageFiles != null && imageFiles.length > 0) {
StringBuilder imageUrls = new StringBuilder();
for (MultipartFile file : imageFiles) {
imageUrls.append(fileService.uploadMinio(file)).append(";");
}
comment.setImageUrls(imageUrls.toString());
}
}
// 工具方法:校验评论类型
private boolean isValidCommentType(String type) {
return "post".equals(type) || "tutorial".equals(type);
}
/** /**
* 获取评论详情接口。 * 获取评论详情接口。
* *
@@ -230,22 +209,8 @@ public class CommentController {
public Result getPostComments(@PathVariable("postId") Long postId, @RequestBody Pages pages) { public Result getPostComments(@PathVariable("postId") Long postId, @RequestBody Pages pages) {
logger.info("获取帖子ID{}的评论列表", postId); logger.info("获取帖子ID{}的评论列表", postId);
logger.info("获取pageSize{}", pages.getPageSize()); logger.info("获取pageSize{}", pages.getPageSize());
IPage<Comment> comments = commentService.getPostComments(postId, pages.getPageNum(), pages.getPageSize()); System.out.println("aaaaaa" + pages.getPageSize());
return Result.ok(comments); PageInfo<Comment> comments = commentService.getPostComments(postId, pages.getPageNum(), pages.getPageSize());
}
/**
* 获取教程下的所有评论。ok
*
* @param tutorialId 帖子的唯一标识ID
* @return 返回操作结果和评论列表
*/
@PostMapping("/tutorial/{tutorialId}")
@Operation(summary = "获取教程下的所有评论")
public Result getTutorialComments(@PathVariable("tutorialId") Long tutorialId, @RequestBody Pages pages) {
logger.info("获取教程ID{}的评论列表", tutorialId);
logger.info("获取pageSize{}", pages.getPageSize());
IPage<Comment> comments = commentService.getTutorialComments(tutorialId, pages.getPageNum(), pages.getPageSize());
return Result.ok(comments); return Result.ok(comments);
} }
@@ -259,39 +224,39 @@ public class CommentController {
@Operation(summary = "获取评论下的所有回复") @Operation(summary = "获取评论下的所有回复")
public Result getCommentReplies(@PathVariable Long commentId, @RequestBody Pages pages) { public Result getCommentReplies(@PathVariable Long commentId, @RequestBody Pages pages) {
logger.info("获取评论ID{}的回复列表", commentId); logger.info("获取评论ID{}的回复列表", commentId);
IPage<Comment> replies = commentService.getCommentReplies(commentId, pages.getPageNum(), pages.getPageSize()); PageInfo<Comment> replies = commentService.getCommentReplies(commentId, pages.getPageNum(), pages.getPageSize());
return Result.ok(replies); return Result.ok(replies);
} }
// /** /**
// * @评论接口。 * @评论接口。
// * *
// * @param comment 包含@信息的评论数据 * @param comment 包含@信息的评论数据
// * @return 返回操作结果 * @return 返回操作结果
// */ */
// @PostMapping("/mention") @PostMapping("/mention")
// @Operation(summary = "@评论") @Operation(summary = "@评论")
// public Result mentionUser(@RequestBody Comment comment) { public Result mentionUser(@RequestBody Comment comment) {
// logger.info("用户ID{}提交@评论请求", StpUtil.getLoginIdAsString()); logger.info("用户ID{}提交@评论请求", StpUtil.getLoginIdAsString());
//
// // 检查父评论是否存在如果有父评论ID // 检查父评论是否存在如果有父评论ID
// if (comment.getParentCommentId() != null) { if (comment.getParentCommentId() != null) {
// Comment parentComment = commentService.getCommentById(comment.getParentCommentId()); Comment parentComment = commentService.getCommentById(comment.getParentCommentId());
// if (parentComment == null) { if (parentComment == null) {
// logger.warn("父评论ID{}不存在", comment.getParentCommentId()); logger.warn("父评论ID{}不存在", comment.getParentCommentId());
// return Result.error("父评论不存在"); return Result.error("父评论不存在");
// } }
// } }
//
// // 检查帖子ID是否存在 // 检查帖子ID是否存在
// if (comment.getPostId() == null) { if (comment.getPostId() == null) {
// logger.warn("帖子ID不能为空"); logger.warn("帖子ID不能为空");
// return Result.error("帖子ID不能为空"); return Result.error("帖子ID不能为空");
// } }
//
// comment.setUserOpenid(StpUtil.getLoginIdAsString()); comment.setUserOpenid(StpUtil.getLoginIdAsString());
// commentService.createComment(comment); commentService.createComment(comment);
// logger.info("@评论创建成功评论ID{}", comment.getCommentId()); logger.info("@评论创建成功评论ID{}", comment.getCommentId());
// return Result.ok(); return Result.ok();
// } }
} }

View File

@@ -4,7 +4,6 @@ import cn.dev33.satoken.annotation.SaCheckLogin;
import com.ivmiku.tutorial.entity.Community; import com.ivmiku.tutorial.entity.Community;
import com.ivmiku.tutorial.response.Result; import com.ivmiku.tutorial.response.Result;
import com.ivmiku.tutorial.service.CommunityService; import com.ivmiku.tutorial.service.CommunityService;
import com.ivmiku.tutorial.service.CommunitytagService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.models.annotations.OpenAPI30; import io.swagger.v3.oas.models.annotations.OpenAPI30;
import org.apiguardian.api.API; import org.apiguardian.api.API;
@@ -49,7 +48,6 @@ public class CommunityController {
* @return 包含社区信息的响应 * @return 包含社区信息的响应
*/ */
@GetMapping("/get/{id}") @GetMapping("/get/{id}")
@Operation(summary = "通过id获取社区信息")
public Result getCommunity(@PathVariable Long id) { public Result getCommunity(@PathVariable Long id) {
Community community = communityService.getById(id); // 根据ID获取社区信息 Community community = communityService.getById(id); // 根据ID获取社区信息
return Result.ok(community); // 返回包含社区信息的成功结果 return Result.ok(community); // 返回包含社区信息的成功结果
@@ -63,7 +61,6 @@ public class CommunityController {
* @return 更新结果的响应 * @return 更新结果的响应
*/ */
@PutMapping("/update/{id}") @PutMapping("/update/{id}")
@Operation(summary = "根据id修改社区")
public Result updateCommunity(@PathVariable Long id, @RequestBody Community community) { public Result updateCommunity(@PathVariable Long id, @RequestBody Community community) {
communityService.updateCommunity(id, community); // 调用服务层更新社区信息 communityService.updateCommunity(id, community); // 调用服务层更新社区信息
return Result.ok(); // 返回成功结果 return Result.ok(); // 返回成功结果
@@ -76,7 +73,6 @@ public class CommunityController {
* @return 删除结果的响应 * @return 删除结果的响应
*/ */
@DeleteMapping("/delete/{id}") @DeleteMapping("/delete/{id}")
@Operation(summary = "删除社区")
public Result deleteCommunity(@PathVariable Long id) { public Result deleteCommunity(@PathVariable Long id) {
communityService.deleteCommunity(id); // 调用服务层删除社区 communityService.deleteCommunity(id); // 调用服务层删除社区
return Result.ok(); // 返回成功结果 return Result.ok(); // 返回成功结果
@@ -89,7 +85,6 @@ public class CommunityController {
* @return 包含社区信息的响应 * @return 包含社区信息的响应
*/ */
@GetMapping("/getByName/{name}") @GetMapping("/getByName/{name}")
@Operation(summary = "根据name获取社区信息")
public Result getCommunityByName(@PathVariable String name) { public Result getCommunityByName(@PathVariable String name) {
logger.info("社区名称为: {}", name); logger.info("社区名称为: {}", name);
List<Community> communitys = communityService.getByName(name); // 根据ID获取社区信息 List<Community> communitys = communityService.getByName(name); // 根据ID获取社区信息
@@ -102,7 +97,6 @@ public class CommunityController {
* @return 包含社区信息的响应 * @return 包含社区信息的响应
*/ */
@GetMapping("/list") @GetMapping("/list")
@Operation(summary = "获取所有社区")
public Result getCommunityList() { public Result getCommunityList() {
List<Community> communities = communityService.getCommunityList(); // 获取社区列表 List<Community> communities = communityService.getCommunityList(); // 获取社区列表
return Result.ok(communities); // 返回包含社区信息的成功结果 return Result.ok(communities); // 返回包含社区信息的成功结果

View File

@@ -1,53 +0,0 @@
package com.ivmiku.tutorial.controller;
import com.ivmiku.tutorial.entity.Communitytag;
import com.ivmiku.tutorial.response.Result;
import com.ivmiku.tutorial.service.CommunitytagService;
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
@RestController
@RequestMapping("/communityTags")
public class CommunitytagController {
@Resource
private CommunitytagService communitytagService;
@PostMapping("/create")
@Operation(summary = "创建社区标签")
public Result createCommunityTag(@RequestBody Communitytag communityTag) {
communitytagService.createCommunityTag(communityTag);
return Result.ok();
}
@PutMapping("/update/{id}")
@Operation(summary = "更新社区标签")
public Result updateCommunityTag(@PathVariable Long id, @RequestBody Communitytag communityTag) {
communitytagService.updateCommunityTag(id, communityTag);
return Result.ok();
}
@DeleteMapping("/delete/{id}")
@Operation(summary = "删除社区标签")
public Result deleteCommunityTag(@PathVariable Long id) {
communitytagService.deleteCommunityTag(id);
return Result.ok();
}
@GetMapping("/get/{id}")
@Operation(summary = "获取社区标签详情")
public Result getCommunityTag(@PathVariable Long id) {
Communitytag communityTag = communitytagService.getCommunityTagById(id);
return Result.ok(communityTag);
}
@GetMapping("/list/{communityId}")
@Operation(summary = "获取社区标签列表")
public Result getCommunityTagListByCommunityId(@PathVariable Long communityId) {
List<Communitytag> tags = communitytagService.getCommunityTagListByCommunityId(communityId);
return Result.ok(tags);
}
}

View File

@@ -2,21 +2,12 @@ package com.ivmiku.tutorial.controller;
import cn.dev33.satoken.annotation.SaCheckLogin; import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.lang.hash.Hash;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ivmiku.tutorial.entity.Pages;
import com.ivmiku.tutorial.entity.Post;
import com.ivmiku.tutorial.entity.Tutorials;
import com.ivmiku.tutorial.response.Result; import com.ivmiku.tutorial.response.Result;
import com.ivmiku.tutorial.service.InteractionService; import com.ivmiku.tutorial.service.InteractionService;
import io.swagger.v3.oas.annotations.Operation;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
/** /**
* InteractionController 是处理用户与帖子的收藏、点赞以及对评论的点赞功能的控制器类。 * InteractionController 是处理用户与帖子的收藏、点赞以及对评论的点赞功能的控制器类。
@@ -37,7 +28,6 @@ public class InteractionController {
* @return 操作结果 * @return 操作结果
*/ */
@PostMapping("/favorite") @PostMapping("/favorite")
@Operation(summary = "对帖子收藏")
public Result favoritePost(@RequestParam Long postId) { public Result favoritePost(@RequestParam Long postId) {
String userOpenid = StpUtil.getLoginIdAsString(); String userOpenid = StpUtil.getLoginIdAsString();
log.info("User {} is favoriting post {}", userOpenid, postId); log.info("User {} is favoriting post {}", userOpenid, postId);
@@ -52,7 +42,6 @@ public class InteractionController {
* @return 操作结果 * @return 操作结果
*/ */
@PostMapping("/likePost") @PostMapping("/likePost")
@Operation(summary = "对帖子点赞")
public Result likePost(@RequestParam Long postId) { public Result likePost(@RequestParam Long postId) {
String userOpenid = StpUtil.getLoginIdAsString(); String userOpenid = StpUtil.getLoginIdAsString();
log.info("User {} is liking post {}", userOpenid, postId); log.info("User {} is liking post {}", userOpenid, postId);
@@ -67,7 +56,6 @@ public class InteractionController {
* @return 操作结果 * @return 操作结果
*/ */
@PostMapping("/likeComment") @PostMapping("/likeComment")
@Operation(summary = "对评论点赞")
public Result likeComment(@RequestParam Long commentId) { public Result likeComment(@RequestParam Long commentId) {
String userOpenid = StpUtil.getLoginIdAsString(); String userOpenid = StpUtil.getLoginIdAsString();
log.info("User {} is liking comment {}", userOpenid, commentId); log.info("User {} is liking comment {}", userOpenid, commentId);
@@ -82,7 +70,6 @@ public class InteractionController {
* @return 操作结果 * @return 操作结果
*/ */
@DeleteMapping("/unfavorite") @DeleteMapping("/unfavorite")
@Operation(summary = "取消收藏帖子")
public Result unfavoritePost(@RequestParam Long postId) { public Result unfavoritePost(@RequestParam Long postId) {
String userOpenid = StpUtil.getLoginIdAsString(); String userOpenid = StpUtil.getLoginIdAsString();
log.info("User {} is unfavoriting post {}", userOpenid, postId); log.info("User {} is unfavoriting post {}", userOpenid, postId);
@@ -97,7 +84,6 @@ public class InteractionController {
* @return 操作结果 * @return 操作结果
*/ */
@DeleteMapping("/unlikePost") @DeleteMapping("/unlikePost")
@Operation(summary = "取消对帖子的点赞")
public Result unlikePost(@RequestParam Long postId) { public Result unlikePost(@RequestParam Long postId) {
String userOpenid = StpUtil.getLoginIdAsString(); String userOpenid = StpUtil.getLoginIdAsString();
log.info("User {} is unliking post {}", userOpenid, postId); log.info("User {} is unliking post {}", userOpenid, postId);
@@ -112,115 +98,10 @@ public class InteractionController {
* @return 操作结果 * @return 操作结果
*/ */
@DeleteMapping("/unlikeComment") @DeleteMapping("/unlikeComment")
@Operation(summary = "取消对评论的点赞")
public Result unlikeComment(@RequestParam Long commentId) { public Result unlikeComment(@RequestParam Long commentId) {
String userOpenid = StpUtil.getLoginIdAsString(); String userOpenid = StpUtil.getLoginIdAsString();
log.info("User {} is unliking comment {}", userOpenid, commentId); log.info("User {} is unliking comment {}", userOpenid, commentId);
interactionService.unlikeComment(userOpenid, commentId); interactionService.unlikeComment(userOpenid, commentId);
return Result.ok(); return Result.ok();
} }
/**
* 我的收藏接口
* @return
*/
@GetMapping("/getFavoritePosts")
@Operation(summary = "获取用户收藏的帖子")
public Result getFavoritePosts(@RequestBody Pages pages) {
String userOpenid = StpUtil.getLoginIdAsString();
log.info("用户 {} 正在获取收藏的帖子", userOpenid);
IPage<Post> favoritePost = interactionService.getFavoritePosts(userOpenid, pages.getPageNum(), pages.getPageSize());
HashMap<String, Object> data = new HashMap<>();
if (favoritePost != null) {
log.info("用户 {} 收藏的帖子获取成功", userOpenid);
data.put("total", favoritePost.getTotal());
data.put("list", favoritePost.getRecords());
return Result.ok(data);
}
return Result.ok("用户未发表帖子");
}
/**
* 统计我的获赞数量 笔记数量 收藏数量
*/
@GetMapping("/getLikeCount")
@Operation(summary = "统计用户获赞数量")
public Result getLikeCount() {
String userOpenid = StpUtil.getLoginIdAsString();
log.info("用户 {} 正在获取用户获赞的数量", userOpenid);
HashMap<String, Object> res = interactionService.getLikeCount(userOpenid);
return Result.ok();
}
/**
* 对官方教程点赞
* @param tutorialId 教程ID
* @return 操作结果
*/
@PostMapping("/likeOfficialTutorial")
@Operation(summary = "对官方教程点赞")
public Result likeOfficialTutorial(@RequestParam Long tutorialId) {
String userOpenid = StpUtil.getLoginIdAsString();
log.info("用户 {} 正在对官方教程 {} 点赞", userOpenid, tutorialId);
interactionService.likeOfficialTutorial(userOpenid, tutorialId);
return Result.ok();
}
/**
* 收藏官方教程
* @param tutorialId 教程ID
* @return 操作结果
*/
@PostMapping("/favoriteOfficialTutorial")
@Operation(summary = "收藏官方教程")
public Result favoriteOfficialTutorial(@RequestParam Long tutorialId) {
String userOpenid = StpUtil.getLoginIdAsString();
log.info("用户 {} 正在收藏官方教程 {}", userOpenid, tutorialId);
interactionService.favoriteOfficialTutorial(userOpenid, tutorialId);
return Result.ok();
}
/**
* 取消对官方教程的点赞
* @param tutorialId 教程ID
* @return 操作结果
*/
@DeleteMapping("/unlikeOfficialTutorial")
@Operation(summary = "取消对官方教程的点赞")
public Result unlikeOfficialTutorial(@RequestParam Long tutorialId) {
String userOpenid = StpUtil.getLoginIdAsString();
log.info("用户 {} 正在取消对官方教程 {} 的点赞", userOpenid, tutorialId);
interactionService.unlikeOfficialTutorial(userOpenid, tutorialId);
return Result.ok();
}
/**
* 取消收藏官方教程
* @param tutorialId 教程ID
* @return 操作结果
*/
@DeleteMapping("/unfavoriteOfficialTutorial")
@Operation(summary = "取消收藏官方教程")
public Result unfavoriteOfficialTutorial(@RequestParam Long tutorialId) {
String userOpenid = StpUtil.getLoginIdAsString();
log.info("用户 {} 正在取消收藏官方教程 {}", userOpenid, tutorialId);
interactionService.unfavoriteOfficialTutorial(userOpenid, tutorialId);
return Result.ok();
}
/**
* 获取用户收藏的官方教程
* @return 用户收藏的官方教程列表
*/
@GetMapping("/getFavoriteOfficialTutorials")
@Operation(summary = "获取用户收藏的官方教程")
public Result getFavoriteOfficialTutorials(@RequestBody Pages pages) {
String userOpenid = StpUtil.getLoginIdAsString();
log.info("用户 {} 正在获取收藏的官方教程", userOpenid);
IPage<Tutorials> favoriteTutorials = interactionService.getFavoriteOfficialTutorials(userOpenid, pages.getPageNum(), pages.getPageSize());
HashMap<String, Object> data = new HashMap<>();
data.put("list", favoriteTutorials);
return Result.ok(data);
}
} }

View File

@@ -1,28 +1,21 @@
package com.ivmiku.tutorial.controller; package com.ivmiku.tutorial.controller;
import cn.dev33.satoken.annotation.SaCheckLogin; import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaIgnore;
import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.pagehelper.PageInfo; import com.github.pagehelper.PageInfo;
import com.ivmiku.tutorial.entity.Pages; import com.ivmiku.tutorial.entity.Pages;
import com.ivmiku.tutorial.entity.Post; import com.ivmiku.tutorial.entity.Post;
import com.ivmiku.tutorial.response.Result; import com.ivmiku.tutorial.response.Result;
import com.ivmiku.tutorial.service.FileService; import com.ivmiku.tutorial.service.FileService;
import com.ivmiku.tutorial.service.PostService; import com.ivmiku.tutorial.service.PostService;
import io.swagger.v3.oas.annotations.Operation;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* 帖子控制器用于处理帖子相关的HTTP请求。 * 帖子控制器用于处理帖子相关的HTTP请求。
@@ -40,20 +33,14 @@ public class PostController {
@Resource @Resource
private FileService fileService; private FileService fileService;
// RedisTemplate 用于存储和检索搜索历史
@Resource
private RedisTemplate redisTemplate;
@PostMapping("/create") @PostMapping("/create")
@Operation(summary = "创建帖子")
public Result createPost(@RequestParam("title") String title, public Result createPost(@RequestParam("title") String title,
@RequestParam("content") String content, @RequestParam("content") String content,
@RequestParam(value = "communityId") Long communityId, @RequestParam("communityId") Long communityId,
@RequestParam(value = "imageFiles", required = false) MultipartFile[] imageFiles, @RequestParam("imageFiles") MultipartFile[] imageFiles,
@RequestParam(value = "videoFile", required = false) MultipartFile videoFile, @RequestParam("videoFile") MultipartFile videoFile,
@RequestParam("isPublic") Integer isPublic, @RequestParam("isPublic") Integer isPublic,
@RequestParam(value = "location", required = false) String location) { @RequestParam("location") String location) {
System.out.println("Aaa");
String userId = StpUtil.getLoginIdAsString(); String userId = StpUtil.getLoginIdAsString();
logger.info("用户ID{}开始创建帖子", userId); logger.info("用户ID{}开始创建帖子", userId);
@@ -92,11 +79,9 @@ public class PostController {
@GetMapping("/get/{id}") @GetMapping("/get/{id}")
@Operation(summary = "获取帖子详细信息")
public Result getPost(@PathVariable Long id) { public Result getPost(@PathVariable Long id) {
logger.info("开始获取帖子ID{}的详细信息", id); logger.info("开始获取帖子ID{}的详细信息", id);
String userId = StpUtil.getLoginIdAsString(); Post post = postService.getPostById(id); // 调用服务层根据ID查询帖子
Post post = postService.getPostById(id, userId); // 调用服务层根据ID查询帖子
if (post != null) { if (post != null) {
logger.info("帖子ID{}的详细信息获取成功", id); logger.info("帖子ID{}的详细信息获取成功", id);
} else { } else {
@@ -106,7 +91,6 @@ public class PostController {
} }
@PutMapping("/update/{id}") @PutMapping("/update/{id}")
@Operation(summary = "更新帖子信息")
public Result updatePost(@PathVariable Long id, @RequestBody Post post) { public Result updatePost(@PathVariable Long id, @RequestBody Post post) {
String userId = StpUtil.getLoginIdAsString(); // 获取当前登录用户的ID String userId = StpUtil.getLoginIdAsString(); // 获取当前登录用户的ID
logger.info("用户ID{}开始更新帖子ID{}", userId, id); logger.info("用户ID{}开始更新帖子ID{}", userId, id);
@@ -116,7 +100,6 @@ public class PostController {
} }
@DeleteMapping("/delete/{id}") @DeleteMapping("/delete/{id}")
@Operation(summary = "删除帖子")
public Result deletePost(@PathVariable Long id) { public Result deletePost(@PathVariable Long id) {
String userId = StpUtil.getLoginIdAsString(); // 获取当前登录用户的ID String userId = StpUtil.getLoginIdAsString(); // 获取当前登录用户的ID
logger.info("用户ID{}开始删除帖子ID{}", userId, id); logger.info("用户ID{}开始删除帖子ID{}", userId, id);
@@ -127,29 +110,24 @@ public class PostController {
/** /**
* 用户获取自己所有帖子的信息 * 用户获取自己所有帖子的信息
* @return 当前用户帖子列表与该用户的总发布数量 * @return 当前用户帖子列表
*/ */
@GetMapping("/getPostList") @GetMapping("/getPostList")
@Operation(summary = "用户获取自己发布的帖子的列表")
public Result getPostList(@RequestBody Pages pages) { public Result getPostList(@RequestBody Pages pages) {
logger.info("开始获取帖子列表"); logger.info("开始获取帖子列表");
String userId = StpUtil.getLoginIdAsString(); // 获取当前登录用户的ID String userId = StpUtil.getLoginIdAsString(); // 获取当前登录用户的ID
IPage<Post> posts = postService.getPostList(userId, pages.getPageNum(), pages.getPageSize()); PageInfo<Post> posts = postService.getPostList(userId, pages.getPageNum(), pages.getPageSize());
Map<String, Object> data = new HashMap<>(); return Result.ok(posts); // 调用服务层获取帖子列表
data.put("total", posts.getTotal());
data.put("posts", posts);
return Result.ok(data); // 调用服务层获取帖子列表
} }
/** /**
* 社区获取自己所有帖子的信息 * 社区获取自己所有帖子的信息
* @return 当前用户帖子列表 * @return 当前用户帖子列表
*/ */
@GetMapping("/getCommunityPostList/{communityId}") @GetMapping("/getCommunityPostList{communityId}")
@Operation(summary = "获取当前社区帖子列表")
public Result getCommunityPostList(@PathVariable("communityId") Long communityId, @RequestBody Pages pages) { public Result getCommunityPostList(@PathVariable("communityId") Long communityId, @RequestBody Pages pages) {
logger.info("开始获取帖子列表"); logger.info("开始获取帖子列表");
IPage<Post> posts = postService.getCommunityPostList(communityId, pages.getPageNum(), pages.getPageSize()); PageInfo<Post> posts = postService.getCommunityPostList(communityId, pages.getPageNum(), pages.getPageSize());
return Result.ok(posts); // 调用服务层获取帖子列表 return Result.ok(posts); // 调用服务层获取帖子列表
} }
@@ -158,8 +136,7 @@ public class PostController {
* @return * @return
*/ */
@GetMapping("/official") @GetMapping("/official")
@Operation(summary = "获取所有官方创建的帖子") public PageInfo<Post> getOfficialPosts(@RequestBody Pages pages) {
public IPage<Post> getOfficialPosts(@RequestBody Pages pages) {
return postService.getOfficialPosts(pages.getPageNum(), pages.getPageSize()); return postService.getOfficialPosts(pages.getPageNum(), pages.getPageSize());
} }
@@ -168,13 +145,11 @@ public class PostController {
* @return * @return
*/ */
@GetMapping("/nonOfficial") @GetMapping("/nonOfficial")
@Operation(summary = "获取所有非官方创建的帖子") public PageInfo<Post> getNonOfficialPosts(@RequestBody Pages pages) {
public IPage<Post> getNonOfficialPosts(@RequestBody Pages pages) {
return postService.getNonOfficialPosts(pages.getPageNum(), pages.getPageSize()); return postService.getNonOfficialPosts(pages.getPageNum(), pages.getPageSize());
} }
@PutMapping("/changePublic") @PutMapping("/changePublic")
@Operation(summary = "修改帖子公开状态")
public Result changePublic(@RequestParam Long postId, @RequestParam Integer isPublic) { public Result changePublic(@RequestParam Long postId, @RequestParam Integer isPublic) {
String userId = StpUtil.getLoginIdAsString(); // 获取当前登录用户的ID String userId = StpUtil.getLoginIdAsString(); // 获取当前登录用户的ID
logger.info("用户ID{}开始修改帖子ID{}的公开状态", userId, postId); logger.info("用户ID{}开始修改帖子ID{}的公开状态", userId, postId);
@@ -182,165 +157,4 @@ public class PostController {
logger.info("用户ID{}的帖子ID{}修改成功", userId, postId); logger.info("用户ID{}的帖子ID{}修改成功", userId, postId);
return Result.ok(); return Result.ok();
} }
@GetMapping("/popularSearches")
@Operation(summary = "获取热门搜索词")
public Result getPopularSearches() {
List<String> popularSearches = postService.getPopularSearches();
return Result.ok(popularSearches);
}
@PostMapping("/searchHistory")
@Operation(summary = "保存搜索历史")
public Result saveSearchHistory(@RequestParam String keyword) {
String userId = StpUtil.getLoginIdAsString();
String key = "search_history:" + userId;
// 保存搜索历史到 Redis 中
redisTemplate.opsForList().rightPush(key, keyword);
// 如果列表长度超过 10 条,删除最早的记录
Long listSize = redisTemplate.opsForList().size(key);
if (listSize != null && listSize > 10) {
redisTemplate.opsForList().leftPop(key); // 删除最早的记录
}
return Result.ok("搜索历史保存成功");
}
/**
* 获取用户的搜索历史
*/
@GetMapping("/searchHistory")
@Operation(summary = "获取用户的搜索历史")
public Result getSearchHistory() {
String userId = StpUtil.getLoginIdAsString();
String key = "search_history:" + userId;
// 从 Redis 中获取搜索历史
List<String> history = redisTemplate.opsForList().range(key, 0, -1);
return Result.ok(history);
}
/**
* 删除用户的搜索历史
*/
@DeleteMapping("/deleteSearchHistory")
@Operation(summary = "删除用户的搜索历史")
public Result deleteSearchHistory() {
String userId = StpUtil.getLoginIdAsString(); // 获取当前登录用户的ID
String key = "search_history:" + userId;
// 删除Redis中的搜索历史
redisTemplate.delete(key);
logger.info("用户ID{}的搜索历史已删除", userId);
return Result.ok("搜索历史已删除");
}
/**
* 根据关键字搜索帖子,包括标题和内容
*/
@GetMapping("/search")
@Operation(summary = "根据关键字搜索帖子")
public Result searchPosts(@RequestParam String keyword) {
// 保存用户搜索历史
saveSearchHistory(keyword);
// 调用服务层方法进行帖子搜索
List<Post> posts = postService.searchPosts(keyword);
return Result.ok(posts);
}
@GetMapping("/topFavorited")
@Operation(summary = "获取用户收藏数量较高的帖子")
public Result getTopFavoritedPosts(@RequestParam(defaultValue = "10") int limit) {
List<Post> topFavoritedPosts = postService.getTopFavoritedPosts(limit);
return Result.ok(topFavoritedPosts);
}
@PostMapping("/saveDraft")
@Operation(summary = "暂存帖子草稿")
public Result saveDraft(@RequestParam("title") String title,
@RequestParam("content") String content,
@RequestParam("communityId") Long communityId,
@RequestParam(value = "imageFiles", required = false) MultipartFile[] imageFiles,
@RequestParam(value = "videoFile", required = false) MultipartFile videoFile,
@RequestParam(value = "location", required = false) String location) {
String userId = StpUtil.getLoginIdAsString();
logger.info("用户ID{} 开始暂存帖子草稿", userId);
Post post = new Post();
post.setUserOpenid(userId);
post.setTitle(title);
post.setContent(content);
post.setCommunityId(communityId);
post.setIsDraft(1); // 0 表示草稿
post.setLocation(location);
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("/getDrafts")
@Operation(summary = "获取用户的所有草稿")
public Result getDrafts() {
String userId = StpUtil.getLoginIdAsString();
logger.info("用户ID{} 开始获取草稿", userId);
List<Post> drafts = postService.getDraftsByUserId(userId);
if (drafts.isEmpty()) {
return Result.error("未找到任何草稿");
}
return Result.ok(drafts);
}
/**
* 猜你喜欢
*/
@GetMapping("/guessYouLike")
@Operation(summary = "猜你喜欢")
public Result guessYouLike(@RequestParam("latitude") Double latitude,
@RequestParam("longitude") Double longitude) {
String userId = StpUtil.getLoginIdAsString();
String key = "search_history:" + userId;
// 获取用户的搜索历史关键词
List<String> searchHistory = redisTemplate.opsForList().range(key, 0, -1);
// 获取猜你喜欢的帖子列表
List<Post> recommendedPosts = postService.getRecommendedPosts(latitude, longitude, searchHistory);
return Result.ok(recommendedPosts);
}
} }

View File

@@ -6,7 +6,6 @@ import com.ivmiku.tutorial.entity.PostTag;
import com.ivmiku.tutorial.entity.Tag; import com.ivmiku.tutorial.entity.Tag;
import com.ivmiku.tutorial.response.Result; import com.ivmiku.tutorial.response.Result;
import com.ivmiku.tutorial.service.PostTagService; import com.ivmiku.tutorial.service.PostTagService;
import io.swagger.v3.oas.annotations.Operation;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -25,7 +24,6 @@ public class PostTagController {
private PostTagService postTagService; private PostTagService postTagService;
@PostMapping("/create") @PostMapping("/create")
@Operation(summary = "创建帖子标签")
public Result createPostTag(@RequestBody PostTag postTag) { public Result createPostTag(@RequestBody PostTag postTag) {
logger.info("开始创建帖子标签"); logger.info("开始创建帖子标签");
postTagService.createPostTag(postTag); postTagService.createPostTag(postTag);
@@ -34,7 +32,6 @@ public class PostTagController {
} }
@GetMapping("/get/{id}") @GetMapping("/get/{id}")
@Operation(summary = "获取帖子标签详细信息")
public Result getPostTag(@PathVariable Long id) { public Result getPostTag(@PathVariable Long id) {
logger.info("开始获取帖子标签ID{}的详细信息", id); logger.info("开始获取帖子标签ID{}的详细信息", id);
PostTag postTag = postTagService.getPostTagById(id); PostTag postTag = postTagService.getPostTagById(id);
@@ -47,7 +44,6 @@ public class PostTagController {
} }
@PutMapping("/update/{id}") @PutMapping("/update/{id}")
@Operation(summary = "更新帖子标签")
public Result updatePostTag(@PathVariable Long id, @RequestBody PostTag postTag) { public Result updatePostTag(@PathVariable Long id, @RequestBody PostTag postTag) {
logger.info("开始更新帖子标签ID{}", id); logger.info("开始更新帖子标签ID{}", id);
postTagService.updatePostTag(id, postTag); postTagService.updatePostTag(id, postTag);
@@ -56,7 +52,6 @@ public class PostTagController {
} }
@DeleteMapping("/delete/{id}") @DeleteMapping("/delete/{id}")
@Operation(summary = "删除帖子标签")
public Result deletePostTag(@PathVariable Long id) { public Result deletePostTag(@PathVariable Long id) {
logger.info("开始删除帖子标签ID{}", id); logger.info("开始删除帖子标签ID{}", id);
postTagService.deletePostTag(id); postTagService.deletePostTag(id);
@@ -65,7 +60,6 @@ public class PostTagController {
} }
@GetMapping("/getPostTagList/{postId}") @GetMapping("/getPostTagList/{postId}")
@Operation(summary = "获取帖子附带的标签列表")
public Result getPostTagList(@PathVariable Long postId) { public Result getPostTagList(@PathVariable Long postId) {
logger.info("开始获取帖子标签列表"); logger.info("开始获取帖子标签列表");
List<Tag> tags = postTagService.getPostTagList(postId); List<Tag> tags = postTagService.getPostTagList(postId);
@@ -73,7 +67,6 @@ public class PostTagController {
} }
@GetMapping("/getTagPostList/{tagId}") @GetMapping("/getTagPostList/{tagId}")
@Operation(summary = "获取标签附带的帖子列表")
public Result getTagPostList(@PathVariable Long tagId) { public Result getTagPostList(@PathVariable Long tagId) {
logger.info("开始获取标签帖子列表"); logger.info("开始获取标签帖子列表");
List<Post> posts = postTagService.getTagPostList(tagId); List<Post> posts = postTagService.getTagPostList(tagId);
@@ -81,7 +74,6 @@ public class PostTagController {
} }
@GetMapping("/topTags") @GetMapping("/topTags")
@Operation(summary = "获取使用次数最多的标签")
public Result getTopTags(@RequestParam(defaultValue = "10") int topN) { public Result getTopTags(@RequestParam(defaultValue = "10") int topN) {
logger.info("开始获取前{}个使用次数最多的标签", topN); logger.info("开始获取前{}个使用次数最多的标签", topN);
List<String> tags = postTagService.getTopTags(topN); List<String> tags = postTagService.getTopTags(topN);

View File

@@ -5,7 +5,6 @@ import com.ivmiku.tutorial.entity.Tag;
import com.ivmiku.tutorial.response.Result; import com.ivmiku.tutorial.response.Result;
import com.ivmiku.tutorial.service.PostTagService; import com.ivmiku.tutorial.service.PostTagService;
import com.ivmiku.tutorial.service.TagService; import com.ivmiku.tutorial.service.TagService;
import io.swagger.v3.oas.annotations.Operation;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -35,7 +34,6 @@ public class TagController {
* @return Result 返回操作结果 * @return Result 返回操作结果
*/ */
@PostMapping("/create") @PostMapping("/create")
@Operation(summary = "创建标签")
public Result createTag(@RequestBody Tag tag) { public Result createTag(@RequestBody Tag tag) {
logger.info("开始创建标签:{}", tag.getName()); logger.info("开始创建标签:{}", tag.getName());
tagService.createTag(tag); tagService.createTag(tag);
@@ -51,7 +49,6 @@ public class TagController {
* @return Result 返回操作结果和标签详情 * @return Result 返回操作结果和标签详情
*/ */
@GetMapping("/get/{id}") @GetMapping("/get/{id}")
@Operation(summary = "获取标签详情")
public Result getTag(@PathVariable Long id) { public Result getTag(@PathVariable Long id) {
logger.info("开始获取标签ID{}的详细信息", id); logger.info("开始获取标签ID{}的详细信息", id);
Tag tag = tagService.getTagById(id); Tag tag = tagService.getTagById(id);
@@ -72,7 +69,6 @@ public class TagController {
* @return Result 返回操作结果 * @return Result 返回操作结果
*/ */
@PutMapping("/update/{id}") @PutMapping("/update/{id}")
@Operation(summary = "更新标签")
public Result updateTag(@PathVariable Long id, @RequestBody Tag tag) { public Result updateTag(@PathVariable Long id, @RequestBody Tag tag) {
logger.info("开始更新标签ID{}的信息", id); logger.info("开始更新标签ID{}的信息", id);
tagService.updateTag(id, tag); tagService.updateTag(id, tag);
@@ -88,7 +84,6 @@ public class TagController {
* @return Result 返回操作结果 * @return Result 返回操作结果
*/ */
@DeleteMapping("/delete/{id}") @DeleteMapping("/delete/{id}")
@Operation(summary = "删除标签")
public Result deleteTag(@PathVariable Long id) { public Result deleteTag(@PathVariable Long id) {
logger.info("开始删除标签ID{}", id); logger.info("开始删除标签ID{}", id);
tagService.deleteTag(id); tagService.deleteTag(id);
@@ -102,7 +97,6 @@ public class TagController {
* @return Result 返回操作结果和标签详情 * @return Result 返回操作结果和标签详情
*/ */
@GetMapping("/getTagList") @GetMapping("/getTagList")
@Operation(summary = "获取所有标签详情")
public Result getTagList() { public Result getTagList() {
List<Tag> tags = tagService.getTagList(); List<Tag> tags = tagService.getTagList();
return Result.ok(tags); return Result.ok(tags);
@@ -113,7 +107,6 @@ public class TagController {
* @return Result 返回操作结果和排序后的标签列表 * @return Result 返回操作结果和排序后的标签列表
*/ */
@GetMapping("/sorted-tag-list") @GetMapping("/sorted-tag-list")
@Operation(summary = "获取排序后的标签列表")
public Result getSortedTagList() { public Result getSortedTagList() {
logger.info("开始获取排序后的标签列表"); logger.info("开始获取排序后的标签列表");
List<Tag> tags = postTagService.getSortedTagList(); List<Tag> tags = postTagService.getSortedTagList();

View File

@@ -1,126 +0,0 @@
package com.ivmiku.tutorial.controller;
import cn.dev33.satoken.stp.StpUtil;
import com.ivmiku.tutorial.entity.Tutorials;
import com.ivmiku.tutorial.response.Result;
import com.ivmiku.tutorial.service.FileService;
import com.ivmiku.tutorial.service.TutorialsService;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
@RestController
@RequestMapping("/tutorial")
@Slf4j
public class TutorialController {
private static final Logger logger = LoggerFactory.getLogger(TutorialController.class);
@Autowired
private TutorialsService tutorialsService;
@Resource
private FileService fileService;
@PostMapping("/create")
@Operation(summary = "创建教程")
public Result createTutorial(@RequestParam("title") String title,
@RequestParam("content") String content,
@RequestParam("tagId") Long tagId,
@RequestParam(value = "imageFile", required = false) MultipartFile imageFile,
@RequestParam(value = "videoFile", required = false) MultipartFile videoFile,
@RequestParam("isOfficial") Integer isOfficial) {
String userId = (String) StpUtil.getLoginId(); // 获取 userOpenid
logger.info("用户ID{} 开始创建教程", userId);
Tutorials tutorial = new Tutorials();
tutorial.setTitle(title);
tutorial.setContent(content);
tutorial.setTagId(tagId);
tutorial.setIsOfficial(isOfficial);
tutorial.setUserOpenid(userId); // 设置 userOpenid
try {
// 上传图片
if (imageFile != null && !imageFile.isEmpty()) {
String uploadResult = fileService.uploadMinio(imageFile);
tutorial.setImageUrl(uploadResult);
}
// 上传视频
if (videoFile != null && !videoFile.isEmpty()) {
String uploadResult = fileService.uploadMinio(videoFile);
tutorial.setVideoUrl(uploadResult);
}
} catch (Exception e) {
logger.error("文件上传失败", e);
return Result.error("文件上传失败");
}
tutorialsService.createTutorial(tutorial);
logger.info("用户ID{} 的教程创建成功", userId);
return Result.ok(tutorial);
}
// 获取教程详细信息
@GetMapping("/get/{id}")
@Operation(summary = "获取教程详细信息")
public Result getTutorial(@PathVariable Long id) {
Tutorials tutorial = tutorialsService.getById(id);
if (tutorial != null) {
return Result.ok(tutorial);
}
return Result.error("未找到教程");
}
// 更新教程
@PutMapping("/update/{id}")
@Operation(summary = "更新教程")
public Result updateTutorial(@PathVariable Long id, @RequestBody Tutorials tutorial) {
tutorial.setTutorialId(id); // 确保教程ID是正确的
boolean updated = tutorialsService.updateById(tutorial);
if (updated) {
return Result.ok("教程更新成功");
}
return Result.error("教程更新失败");
}
// 删除教程
@DeleteMapping("/delete/{id}")
@Operation(summary = "删除教程")
public Result deleteTutorial(@PathVariable Long id) {
boolean deleted = tutorialsService.removeById(id);
if (deleted) {
return Result.ok("教程删除成功");
}
return Result.error("教程删除失败");
}
// 获取所有教程
@GetMapping("/list")
@Operation(summary = "获取所有教程")
public Result listTutorials() {
List<Tutorials> tutorials = tutorialsService.list();
return Result.ok(tutorials);
}
// 根据教程标签ID获取教程列表
@GetMapping("/listByTag/{tagId}")
@Operation(summary = "根据教程标签ID获取教程列表")
public Result listTutorialsByTag(@PathVariable Long tagId) {
List<Tutorials> tutorials = tutorialsService.getTutorialsByTagId(tagId);
if (tutorials.isEmpty()) {
return Result.error("未找到对应标签的教程");
}
return Result.ok(tutorials);
}
}

View File

@@ -1,61 +0,0 @@
package com.ivmiku.tutorial.controller;
import com.ivmiku.tutorial.entity.TutorialTags;
import com.ivmiku.tutorial.response.Result;
import com.ivmiku.tutorial.service.TutorialTagsService;
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/tutorialTags")
public class TutorialTagsController {
@Autowired
private TutorialTagsService tutorialTagsService;
@PostMapping("/create")
@Operation(summary = "创建教程标签")
public Result createTag(@RequestParam("tagName") String tagName,
@RequestParam("isOfficial") Integer isOfficial) {
TutorialTags tag = new TutorialTags();
tag.setTagName(tagName);
tag.setIsOfficial(isOfficial);
tutorialTagsService.createTag(tag);
return Result.ok(tag);
}
@GetMapping("/getAll")
@Operation(summary = "获取所有教程标签")
public Result getAllTags() {
List<TutorialTags> tags = tutorialTagsService.getAllTags();
return Result.ok(tags);
}
@PutMapping("/update")
@Operation(summary = "更新教程标签")
public Result updateTag(@RequestParam("tagId") Long tagId,
@RequestParam("tagName") String tagName,
@RequestParam("isOfficial") Integer isOfficial) {
TutorialTags tag = tutorialTagsService.getTagById(tagId);
if (tag == null) {
return Result.error("标签不存在");
}
tag.setTagName(tagName);
tag.setIsOfficial(isOfficial);
tutorialTagsService.updateTag(tag);
return Result.ok(tag);
}
@DeleteMapping("/delete")
@Operation(summary = "删除教程标签")
public Result deleteTag(@RequestParam("tagId") Long tagId) {
tutorialTagsService.deleteTag(tagId);
return Result.ok("标签已删除");
}
}

View File

@@ -1,80 +0,0 @@
package com.ivmiku.tutorial.controller;
import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.fastjson.JSON;
import com.ivmiku.tutorial.entity.UserDTO;
import com.ivmiku.tutorial.response.Result;
import com.ivmiku.tutorial.service.impl.SearchService;
import jakarta.websocket.*;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Controller;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Controller
@ServerEndpoint(value = "/search/{satoken}")
public class WebSocketServer implements ApplicationContextAware {
public static Map<String, Session> sessionMap = new ConcurrentHashMap<>();
private static ApplicationContext applicationContext;
private SearchService searchService;
@OnOpen
public void onOpen(Session session, EndpointConfig endpointConfig, @PathParam("satoken") String satoken) throws IOException {
String userId = (String) StpUtil.getLoginIdByToken(satoken);
if (userId == null) {
session.getBasicRemote().sendText("Invalid Token");
session.close();
}
sessionMap.put(userId, session);
this.searchService = WebSocketServer.applicationContext.getBean(SearchService.class);
}
@OnClose
public void onClose(CloseReason closeReason, Session session){
sessionMap.remove(session.getId());
}
@OnError
public void onError(Throwable throwable) throws IOException {
throwable.printStackTrace();
}
@OnMessage
public void onMessage(String message, Session session) throws IOException {
char first = message.charAt(0);
String userId = null;
for (Map.Entry<String, Session> entry : sessionMap.entrySet()) {
if (entry.getValue().equals(session)) {
userId = entry.getKey();
}
}
switch (first) {
case '@' -> {
String sub = message.substring(1);
List<UserDTO> result = searchService.getUserList(sub, userId);
session.getBasicRemote().sendText(JSON.toJSONString(Result.ok(result)));
}
case '#' -> {
String sub = message.substring(1);
List<String> list = searchService.getTag(sub);
session.getBasicRemote().sendText(JSON.toJSONString(Result.ok(list)));
}
//预留给社区搜索
default -> {
}
}
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
WebSocketServer.applicationContext = applicationContext;
}
}

View File

@@ -1,30 +0,0 @@
package com.ivmiku.tutorial.entity;
import com.baomidou.mybatisplus.annotation.*;
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
/**
* @TableName browing_history
*/
@TableName(value ="browing_history")
@Data
public class BrowingHistory implements Serializable {
@TableId(type = IdType.AUTO)
private Long browingId;
private String userOpenid;
private Long postId;
private Date createAt;
@TableLogic
private Integer isDelete;
private static final long serialVersionUID = 1L;
}

View File

@@ -21,9 +21,6 @@ public class Comment implements Serializable {
private Long postId; private Long postId;
@TableField("tutorialId")
private Long tutorialId; // 新增字段
private String content; private String content;
private Long parentCommentId; private Long parentCommentId;

View File

@@ -1,27 +0,0 @@
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 communitytag
*/
@TableName(value ="communitytag")
@Data
public class Communitytag implements Serializable {
@TableId
private Long smallCTagId;
private String cTagName;
private Long cId;
private Integer isDelete;
private static final long serialVersionUID = 1L;
}

View File

@@ -22,7 +22,5 @@ public class Favorite implements Serializable {
private Integer isDeleted; private Integer isDeleted;
private Long tutorialId; // 新增字段
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
} }

View File

@@ -20,8 +20,6 @@ public class Likee implements Serializable {
private Long commentId; private Long commentId;
private Long tutorialId; // 新增字段
private Integer isDeleted; private Integer isDeleted;
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

View File

@@ -37,13 +37,9 @@ public class Post implements Serializable {
private String location; // 存储帖子位置信息 private String location; // 存储帖子位置信息
private Integer isDraft; // 是否为草稿 0不是 1是
private Date createdAt; private Date createdAt;
private Date updatedAt; private Date updatedAt;
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
} }

View File

@@ -1,13 +0,0 @@
package com.ivmiku.tutorial.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
/**
* @author Aurora
*/
@TableName("subscribe")
@Data
public class Subscribe {
private Long id;
private Long subId;
}

View File

@@ -1,25 +0,0 @@
package com.ivmiku.tutorial.entity;
import com.baomidou.mybatisplus.annotation.*;
import java.io.Serializable;
import lombok.Data;
/**
* @TableName tutorial_tags
*/
@TableName(value ="tutorial_tags")
@Data
public class TutorialTags implements Serializable {
@TableId(type = IdType.AUTO)
private Long tagId;
private String tagName;
private Integer isOfficial;
@TableLogic
private Integer isDeleted;
private static final long serialVersionUID = 1L;
}

View File

@@ -1,38 +0,0 @@
package com.ivmiku.tutorial.entity;
import com.baomidou.mybatisplus.annotation.*;
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
/**
* @TableName tutorials
*/
@TableName(value ="tutorials")
@Data
public class Tutorials implements Serializable {
@TableId(type = IdType.AUTO)
private Long tutorialId;
private String title;
private String content;
private String imageUrl;
private String videoUrl;
private Integer isOfficial;
@TableLogic
private Integer isDeleted;
private Date createdAt;
private Long tagId;
private String userOpenid; // 新增的字段
private static final long serialVersionUID = 1L;
}

View File

@@ -4,15 +4,11 @@ import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data; import lombok.Data;
@TableName("user")
@Data @Data
@TableName("User")
public class User { public class User {
@TableId @TableId
private String openid; private String openid;
private String nickname; private String nickname;
private String avatarUrl; private String avatarUrl;
private boolean isAdmin;
private String phoneNum;
private String birthday;
private String gender;
} }

View File

@@ -1,12 +0,0 @@
package com.ivmiku.tutorial.entity;
import lombok.Data;
@Data
public class UserDTO {
private String nickname;
private String avatarUrl;
private String phoneNum;
private String birthday;
private String gender;
}

View File

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

View File

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

View File

@@ -2,8 +2,6 @@ package com.ivmiku.tutorial.mapper;
import com.ivmiku.tutorial.entity.Likee; import com.ivmiku.tutorial.entity.Likee;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
/** /**
* @author rog * @author rog
@@ -13,17 +11,6 @@ import org.apache.ibatis.annotations.Select;
*/ */
public interface LikeMapper extends BaseMapper<Likee> { public interface LikeMapper extends BaseMapper<Likee> {
// 获取帖子获赞数
Long getPostLikeCount(@Param("userOpenid") String userOpenid);
// 获取评论获赞数
Long getCommentLikeCount(@Param("userOpenid") String userOpenid);
// 查询帖子被点赞的总数
Long getLikeCountByPostId(@Param("postId") Long postId);
} }

View File

@@ -17,18 +17,6 @@ public interface PostMapper extends BaseMapper<Post> {
List<Post> getTagPostList(Long tagId); List<Post> getTagPostList(Long tagId);
List<String> selectPopularSearches();
List<Post> searchPosts(String keyword);
List<Post> getTopFavoritedPosts(int limit);
List<Post> getPostsBasedOnHistoryAndHotness(Long userId, List<String> searchHistory);
@Select("SELECT * FROM post WHERE ST_Distance_Sphere(point(location_lng, location_lat), point(#{longitude}, #{latitude})) < 50000") // 50km 范围
List<Post> getPostsNearby(Double latitude, Double longitude);
} }

View File

@@ -1,8 +0,0 @@
package com.ivmiku.tutorial.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ivmiku.tutorial.entity.Subscribe;
public interface SubscribeMapper extends BaseMapper<Subscribe> {
}

View File

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

View File

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

View File

@@ -1,7 +0,0 @@
package com.ivmiku.tutorial.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ivmiku.tutorial.entity.User;
public interface UserMapper extends BaseMapper<User> {
}

View File

@@ -1,18 +0,0 @@
package com.ivmiku.tutorial.service;
import com.ivmiku.tutorial.entity.BrowingHistory;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/**
* @author rog
* @description 针对表【browing_history】的数据库操作Service
* @createDate 2024-08-23 11:29:33
*/
public interface BrowingHistoryService extends IService<BrowingHistory> {
void deleteBrowingRecordById(Long browingId);
void deleteBrowingRecordsByIds(List<Long> browingIds);
}

View File

@@ -1,6 +1,5 @@
package com.ivmiku.tutorial.service; package com.ivmiku.tutorial.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.pagehelper.PageInfo; import com.github.pagehelper.PageInfo;
import com.ivmiku.tutorial.entity.Comment; import com.ivmiku.tutorial.entity.Comment;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
@@ -51,9 +50,9 @@ public interface CommentService extends IService<Comment> {
void deleteComment(Long commentId, String userId); void deleteComment(Long commentId, String userId);
IPage<Comment> getPostComments(Long postId, int pageNum, int pageSize); PageInfo<Comment> getPostComments(Long postId, int pageNum, int pageSize);
IPage<Comment> getCommentReplies(Long commentId, int pageNum, int pageSize); PageInfo<Comment> getCommentReplies(Long commentId, int pageNum, int pageSize);
/** /**
* 回复评论。 * 回复评论。
@@ -68,5 +67,5 @@ public interface CommentService extends IService<Comment> {
void createReply(Long parentCommentId, Long postId, String content, String mentionedUserId); void createReply(Long parentCommentId, Long postId, String content, String mentionedUserId);
IPage<Comment> getTutorialComments(Long tutorialId, Integer pageNum, Integer pageSize);
} }

View File

@@ -1,24 +0,0 @@
package com.ivmiku.tutorial.service;
import com.ivmiku.tutorial.entity.Communitytag;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/**
* @author rog
* @description 针对表【communitytag】的数据库操作Service
* @createDate 2024-08-16 09:40:06
*/
public interface CommunitytagService extends IService<Communitytag> {
void createCommunityTag(Communitytag communityTag);
void updateCommunityTag(Long id, Communitytag communityTag);
void deleteCommunityTag(Long id);
Communitytag getCommunityTagById(Long id);
List<Communitytag> getCommunityTagListByCommunityId(Long communityId);
}

View File

@@ -1,12 +1,5 @@
package com.ivmiku.tutorial.service; package com.ivmiku.tutorial.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.ivmiku.tutorial.entity.Post;
import com.ivmiku.tutorial.entity.Tutorials;
import java.util.HashMap;
import java.util.List;
/** /**
* InteractionService接口定义用户对帖子和评论的收藏与点赞操作。 * InteractionService接口定义用户对帖子和评论的收藏与点赞操作。
*/ */
@@ -17,20 +10,4 @@ public interface InteractionService {
void unlikePost(String userOpenid, Long postId); void unlikePost(String userOpenid, Long postId);
void likeComment(String userOpenid, Long commentId); void likeComment(String userOpenid, Long commentId);
void unlikeComment(String userOpenid, Long commentId); void unlikeComment(String userOpenid, Long commentId);
IPage<Post> getFavoritePosts(String userOpenid, int pageNum, int pageSize);
HashMap<String, Object> getLikeCount(String userOpenid);
void likeOfficialTutorial(String userOpenid, Long tutorialId);
void favoriteOfficialTutorial(String userOpenid, Long tutorialId);
void unlikeOfficialTutorial(String userOpenid, Long tutorialId);
void unfavoriteOfficialTutorial(String userOpenid, Long tutorialId);
IPage<Tutorials> getFavoriteOfficialTutorials(String userOpenid, int pageNum, int pageSize);
// 新增方法:根据帖子 ID 获取点赞总数
Long getLikeCountByPostId(Long postId);
} }

View File

@@ -1,6 +1,5 @@
package com.ivmiku.tutorial.service; package com.ivmiku.tutorial.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.pagehelper.PageInfo; import com.github.pagehelper.PageInfo;
import com.ivmiku.tutorial.entity.Post; import com.ivmiku.tutorial.entity.Post;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
@@ -9,30 +8,17 @@ import java.util.List;
public interface PostService extends IService<Post> { public interface PostService extends IService<Post> {
void createPost(Post post); void createPost(Post post);
Post getPostById(Long postId, String userOpenid); Post getPostById(Long postId);
void updatePost(Long postId, String userId, Post post); void updatePost(Long postId, String userId, Post post);
void deletePost(Long postId, String userId); void deletePost(Long postId, String userId);
IPage<Post> getPostList(String userId, int pageNum, int pageSize); PageInfo<Post> getPostList(String userId, int pageNum, int pageSize);
IPage<Post> getCommunityPostList(Long communityId, int pageNum, int pageSize); PageInfo<Post> getCommunityPostList(Long communityId, int pageNum, int pageSize);
IPage<Post> getOfficialPosts(int pageNum, int pageSize); PageInfo<Post> getOfficialPosts(int pageNum, int pageSize);
IPage<Post> getNonOfficialPosts(int pageNum, int pageSize); PageInfo<Post> getNonOfficialPosts(int pageNum, int pageSize);
void changePublic(Long postId, Integer isPublic); void changePublic(Long postId, Integer isPublic);
List<String> getPopularSearches();
List<Post> searchPosts(String keyword);
List<Post> getTopFavoritedPosts(int limit);
List<Post> getDraftsByUserId(String userId);
List<Post> getRecommendedPosts(Double latitude, Double longitude, List<String> searchHistory);
} }

View File

@@ -1,25 +0,0 @@
package com.ivmiku.tutorial.service;
import com.ivmiku.tutorial.entity.TutorialTags;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/**
* @author rog
* @description 针对表【tutorial_tags】的数据库操作Service
* @createDate 2024-08-29 21:15:08
*/
public interface TutorialTagsService extends IService<TutorialTags> {
void createTag(TutorialTags tag);
List<TutorialTags> getAllTags();
TutorialTags getTagById(Long tagId);
void updateTag(TutorialTags tag);
void deleteTag(Long tagId);
}

View File

@@ -1,20 +0,0 @@
package com.ivmiku.tutorial.service;
import com.ivmiku.tutorial.entity.Tutorials;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/**
* @author rog
* @description 针对表【tutorials】的数据库操作Service
* @createDate 2024-08-29 21:14:50
*/
public interface TutorialsService extends IService<Tutorials> {
void createTutorial(Tutorials tutorial);
List<Tutorials> getTutorialsByTagId(Long tagId);
List<Tutorials> getTutorialsByIds(List<Long> tutorialIds);
}

View File

@@ -1,60 +0,0 @@
package com.ivmiku.tutorial.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ivmiku.tutorial.entity.BrowingHistory;
import com.ivmiku.tutorial.service.BrowingHistoryService;
import com.ivmiku.tutorial.mapper.BrowingHistoryMapper;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @author rog
* @description 针对表【browing_history】的数据库操作Service实现
* @createDate 2024-08-23 11:29:33
*/
@Service
@Slf4j
public class BrowingHistoryServiceImpl extends ServiceImpl<BrowingHistoryMapper, BrowingHistory>
implements BrowingHistoryService{
private static final Logger logger = LoggerFactory.getLogger(BrowingHistoryServiceImpl.class);
@Override
public void deleteBrowingRecordById(Long browingId) {
logger.info("开始删除浏览记录浏览记录ID{}", browingId);
BrowingHistory browingHistory = getById(browingId);
if (browingHistory != null) {
browingHistory.setIsDelete(1); // 标记为已删除
updateById(browingHistory);
logger.info("浏览记录ID{} 删除成功", browingId);
} else {
logger.warn("浏览记录ID{} 不存在", browingId);
}
}
@Override
public void deleteBrowingRecordsByIds(List<Long> browingIds) {
logger.info("开始批量删除浏览记录浏览记录ID列表{}", browingIds);
if (browingIds != null && !browingIds.isEmpty()) {
List<BrowingHistory> browingHistories = listByIds(browingIds);
if (!browingHistories.isEmpty()) {
for (BrowingHistory browingHistory : browingHistories) {
browingHistory.setIsDelete(1); // 标记为已删除
}
updateBatchById(browingHistories); // 批量更新删除状态
logger.info("批量删除浏览记录成功");
} else {
logger.warn("提供的浏览记录ID列表中没有找到匹配的记录");
}
} else {
logger.warn("浏览记录ID列表为空无法删除");
}
}
}

View File

@@ -1,21 +1,15 @@
package com.ivmiku.tutorial.service.impl; package com.ivmiku.tutorial.service.impl;
import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo; import com.github.pagehelper.PageInfo;
import com.ivmiku.tutorial.entity.Comment; import com.ivmiku.tutorial.entity.Comment;
import com.ivmiku.tutorial.mapper.CommentMapper; import com.ivmiku.tutorial.mapper.CommentMapper;
import com.ivmiku.tutorial.response.AtNotifier;
import com.ivmiku.tutorial.service.CommentService; import com.ivmiku.tutorial.service.CommentService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@@ -34,9 +28,6 @@ public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> impl
@Autowired @Autowired
protected CommentMapper commentMapper; protected CommentMapper commentMapper;
@Resource
private RabbitTemplate rabbitTemplate;
/** /**
* 保存评论。 * 保存评论。
* 将评论数据保存到数据库。 * 将评论数据保存到数据库。
@@ -112,17 +103,16 @@ public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> impl
* @return List<Comment> 返回评论列表 * @return List<Comment> 返回评论列表
*/ */
@Override @Override
public IPage<Comment> getPostComments(Long postId, int pageNum, int pageSize) { public PageInfo<Comment> getPostComments(Long postId, int pageNum, int pageSize) {
logger.info("开始获取帖子ID{}的评论列表,第{}页,每页{}条", postId, pageNum, pageSize); logger.info("开始获取帖子ID{}的评论列表,第{}页,每页{}条", postId, pageNum, pageSize);
// 设置分页参数 // 设置分页参数
// PageHelper.startPage(pageNum, pageSize); PageHelper.startPage(pageNum, pageSize);
IPage<Comment> page = new Page<>(pageNum, pageSize);
// 查询评论 // 查询评论
LambdaQueryWrapper<Comment> wrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<Comment> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Comment::getPostId, postId).eq(Comment::getIsDeleted, 0); wrapper.eq(Comment::getPostId, postId).eq(Comment::getIsDeleted, 0);
IPage<Comment> comments = commentMapper.selectPage(page, wrapper); List<Comment> comments = commentMapper.selectList(wrapper);
if (comments != null) { if (comments != null) {
logger.info("获取帖子ID{}的评论列表成功", postId); logger.info("获取帖子ID{}的评论列表成功", postId);
@@ -131,7 +121,7 @@ public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> impl
} }
// 使用 PageInfo 包装结果 // 使用 PageInfo 包装结果
return comments; return new PageInfo<>(comments);
} }
@@ -142,16 +132,16 @@ public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> impl
* @return List<Comment> 返回回复列表 * @return List<Comment> 返回回复列表
*/ */
@Override @Override
public IPage<Comment> getCommentReplies(Long commentId, int pageNum, int pageSize) { public PageInfo<Comment> getCommentReplies(Long commentId, int pageNum, int pageSize) {
logger.info("开始获取评论ID{}的回复列表,第{}页,每页{}条", commentId, pageNum, pageSize); logger.info("开始获取评论ID{}的回复列表,第{}页,每页{}条", commentId, pageNum, pageSize);
// 设置分页参数 // 设置分页参数
// PageHelper.startPage(pageNum, pageSize); PageHelper.startPage(pageNum, pageSize);
IPage<Comment> page = new Page<>(pageNum, pageSize);
// 查询回复 // 查询回复
LambdaQueryWrapper<Comment> wrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<Comment> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Comment::getParentCommentId, commentId).eq(Comment::getIsDeleted, 0); wrapper.eq(Comment::getParentCommentId, commentId).eq(Comment::getIsDeleted, 0);
IPage<Comment> replies = commentMapper.selectPage(page, wrapper); List<Comment> replies = commentMapper.selectList(wrapper);
if (replies != null) { if (replies != null) {
logger.info("获取评论ID{}的回复列表成功", commentId); logger.info("获取评论ID{}的回复列表成功", commentId);
@@ -160,7 +150,7 @@ public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> impl
} }
// 使用 PageInfo 包装结果 // 使用 PageInfo 包装结果
return replies; return new PageInfo<>(replies);
} }
/** /**
* 回复评论。 * 回复评论。
@@ -193,38 +183,8 @@ public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> impl
reply.setMentionedUserId(mentionedUserId); reply.setMentionedUserId(mentionedUserId);
} }
createComment(reply); createComment(reply);
if (mentionedUserId != null) {
AtNotifier notifier = new AtNotifier();
notifier.setFromId(reply.getUserOpenid());
notifier.setToId(mentionedUserId);
notifier.setPostId(String.valueOf(reply.getCommentId()));
rabbitTemplate.convertAndSend("exchange2", "", JSON.toJSONString(notifier));
}
logger.info("评论回复成功评论ID{}", reply.getCommentId()); logger.info("评论回复成功评论ID{}", reply.getCommentId());
} }
@Override
public IPage<Comment> getTutorialComments(Long tutorialId, Integer pageNum, Integer pageSize) {
logger.info("开始获取帖子ID{}的评论列表,第{}页,每页{}条", tutorialId, pageNum, pageSize);
// 设置分页参数
// PageHelper.startPage(pageNum, pageSize);
IPage<Comment> page = new Page<>(pageNum, pageSize);
// 查询评论
LambdaQueryWrapper<Comment> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Comment::getTutorialId, tutorialId).eq(Comment::getIsDeleted, 0);
IPage<Comment> comments = commentMapper.selectPage(page, wrapper);
if (comments != null) {
logger.info("获取教程ID{}的评论列表成功", tutorialId);
} else {
logger.warn("教程ID{}的评论列表为空", tutorialId);
}
// 使用 PageInfo 包装结果
return comments;
}
} }

View File

@@ -1,50 +0,0 @@
package com.ivmiku.tutorial.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ivmiku.tutorial.entity.Communitytag;
import com.ivmiku.tutorial.service.CommunitytagService;
import com.ivmiku.tutorial.mapper.CommunitytagMapper;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @author rog
* @description 针对表【communitytag】的数据库操作Service实现
* @createDate 2024-08-16 09:40:06
*/
@Service
public class CommunitytagServiceImpl extends ServiceImpl<CommunitytagMapper, Communitytag>
implements CommunitytagService{
@Override
public void createCommunityTag(Communitytag communityTag) {
this.save(communityTag);
}
@Override
public void updateCommunityTag(Long id, Communitytag communityTag) {
communityTag.setSmallCTagId(id);
this.updateById(communityTag);
}
@Override
public void deleteCommunityTag(Long id) {
this.removeById(id);
}
@Override
public Communitytag getCommunityTagById(Long id) {
return this.getById(id);
}
@Override
public List<Communitytag> getCommunityTagListByCommunityId(Long communityId) {
return this.lambdaQuery().eq(Communitytag::getCId, communityId).list();
}
}

View File

@@ -1,26 +1,15 @@
package com.ivmiku.tutorial.service.impl; package com.ivmiku.tutorial.service.impl;
import cn.hutool.core.lang.hash.Hash;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ivmiku.tutorial.entity.Favorite; import com.ivmiku.tutorial.entity.Favorite;
import com.ivmiku.tutorial.entity.Likee; import com.ivmiku.tutorial.entity.Likee;
import com.ivmiku.tutorial.entity.Post;
import com.ivmiku.tutorial.entity.Tutorials;
import com.ivmiku.tutorial.mapper.FavoriteMapper; import com.ivmiku.tutorial.mapper.FavoriteMapper;
import com.ivmiku.tutorial.mapper.LikeMapper; import com.ivmiku.tutorial.mapper.LikeMapper;
import com.ivmiku.tutorial.service.InteractionService; import com.ivmiku.tutorial.service.InteractionService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ivmiku.tutorial.service.PostService;
import com.ivmiku.tutorial.service.TutorialsService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/** /**
* InteractionServiceImpl 实现了 InteractionService 接口,处理用户对帖子和评论的收藏与点赞操作。 * InteractionServiceImpl 实现了 InteractionService 接口,处理用户对帖子和评论的收藏与点赞操作。
@@ -35,12 +24,6 @@ public class InteractionServiceImpl implements InteractionService {
@Resource @Resource
private LikeMapper likeMapper; private LikeMapper likeMapper;
@Resource
private PostService postService;
@Resource
private TutorialsService tutorialService;
@Override @Override
public void favoritePost(String userOpenid, Long postId) { public void favoritePost(String userOpenid, Long postId) {
log.info("User {} is favoriting post {}", userOpenid, postId); log.info("User {} is favoriting post {}", userOpenid, postId);
@@ -112,149 +95,4 @@ public class InteractionServiceImpl implements InteractionService {
likeMapper.updateById(likee); likeMapper.updateById(likee);
} }
} }
@Override
public IPage<Post> getFavoritePosts(String userOpenid, int pageNum, int pageSize) {
LambdaQueryWrapper<Favorite> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Favorite::getUserOpenid, userOpenid);
List<Favorite> favorites = favoriteMapper.selectList(wrapper);
if (favorites != null && !favorites.isEmpty()) {
List<Long> postIds = favorites.stream().map(Favorite::getPostId).toList();
return postService.getPostList(userOpenid, pageNum, pageSize);
}
return null;
}
@Override
public HashMap<String, Object> getLikeCount(String userOpenid) {
HashMap<String, Object> res = new HashMap<>();
// 获取帖子获赞数
Long postLikeCount = likeMapper.getPostLikeCount(userOpenid);
// 获取评论获赞数
Long commentLikeCount = likeMapper.getCommentLikeCount(userOpenid);
// 如果帖子获赞数不为空,加入结果
if (postLikeCount != null) {
res.put("postLikeCount", postLikeCount);
} else {
res.put("postLikeCount", 0L); // 如果为空设置为0
}
// 如果评论获赞数不为空,加入结果
if (commentLikeCount != null) {
res.put("commentLikeCount", commentLikeCount);
} else {
res.put("commentLikeCount", 0L); // 如果为空设置为0
}
// 计算总的获赞数
Long totalLikeCount = (postLikeCount == null ? 0 : postLikeCount) +
(commentLikeCount == null ? 0 : commentLikeCount);
res.put("totalLikeCount", totalLikeCount);
// 获取收藏数量
LambdaQueryWrapper<Favorite> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Favorite::getUserOpenid, userOpenid);
Long favoriteCount = favoriteMapper.selectCount(wrapper);
if (favoriteCount != null) {
res.put("favoriteCount", favoriteCount);
} else {
res.put("favoriteCount", 0L); // 如果为空设置为0
}
return res;
}
@Override
public void likeOfficialTutorial(String userOpenid, Long tutorialId) {
log.info("User {} is liking tutorial {}", userOpenid, tutorialId);
Likee likee = new Likee();
likee.setUserOpenid(userOpenid);
likee.setTutorialId(tutorialId);
likee.setIsDeleted(0);
likeMapper.insert(likee);
}
@Override
public void favoriteOfficialTutorial(String userOpenid, Long tutorialId) {
log.info("User {} is favoriting tutorial {}", userOpenid, tutorialId);
Favorite favorite = new Favorite();
favorite.setUserOpenid(userOpenid);
favorite.setTutorialId(tutorialId);
favorite.setIsDeleted(0);
favoriteMapper.insert(favorite);
}
@Override
public void unlikeOfficialTutorial(String userOpenid, Long tutorialId) {
log.info("User {} is unliking tutorial {}", userOpenid, tutorialId);
QueryWrapper<Likee> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("user_openid", userOpenid)
.eq("tutorial_id", tutorialId)
.eq("is_deleted", 0);
Likee likee = likeMapper.selectOne(queryWrapper);
if (likee != null) {
likee.setIsDeleted(1);
likeMapper.updateById(likee);
}
}
@Override
public void unfavoriteOfficialTutorial(String userOpenid, Long tutorialId) {
log.info("User {} is unfavoriting tutorial {}", userOpenid, tutorialId);
QueryWrapper<Favorite> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("user_openid", userOpenid)
.eq("tutorial_id", tutorialId)
.eq("is_deleted", 0);
Favorite favorite = favoriteMapper.selectOne(queryWrapper);
if (favorite != null) {
favorite.setIsDeleted(1);
favoriteMapper.updateById(favorite);
}
}
@Override
public IPage<Tutorials> getFavoriteOfficialTutorials(String userOpenid, int pageNum, int pageSize) {
// 创建分页对象
IPage<Favorite> page = new Page<>(pageNum, pageSize);
// 创建查询条件,筛选出用户收藏的且未被删除的教程
LambdaQueryWrapper<Favorite> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Favorite::getUserOpenid, userOpenid)
.isNotNull(Favorite::getTutorialId) // 确保教程ID不为空
.eq(Favorite::getIsDeleted, 0); // 只获取未删除的收藏记录
// 分页查询收藏的教程ID
IPage<Favorite> favoritePage = favoriteMapper.selectPage(page, wrapper);
// 提取出所有收藏的教程ID
List<Long> tutorialIds = favoritePage.getRecords().stream()
.map(Favorite::getTutorialId)
.toList();
if (tutorialIds.isEmpty()) {
return new Page<>(); // 如果没有收藏记录,返回空的分页对象
}
// 通过教程ID列表查询对应的教程实体并将分页结果映射到教程分页
List<Tutorials> tutorials = tutorialService.getTutorialsByIds(tutorialIds);
// 创建一个新的分页对象,用于返回教程数据
IPage<Tutorials> tutorialPage = new Page<>(pageNum, pageSize);
tutorialPage.setRecords(tutorials);
tutorialPage.setTotal(favoritePage.getTotal()); // 设置总记录数
return tutorialPage;
}
@Override
public Long getLikeCountByPostId(Long postId) {
log.info("Fetching like count for post {}", postId);
return likeMapper.getLikeCountByPostId(postId);
}
} }

View File

@@ -1,28 +1,19 @@
package com.ivmiku.tutorial.service.impl; package com.ivmiku.tutorial.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.github.pagehelper.PageHelper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.github.pagehelper.PageInfo;
import com.ivmiku.tutorial.entity.BrowingHistory;
import com.ivmiku.tutorial.entity.Post; import com.ivmiku.tutorial.entity.Post;
import com.ivmiku.tutorial.mapper.CommentMapper;
import com.ivmiku.tutorial.mapper.FavoriteMapper;
import com.ivmiku.tutorial.mapper.LikeMapper;
import com.ivmiku.tutorial.mapper.PostMapper; import com.ivmiku.tutorial.mapper.PostMapper;
import com.ivmiku.tutorial.service.BrowingHistoryService;
import com.ivmiku.tutorial.service.InteractionService;
import com.ivmiku.tutorial.service.PostService; import com.ivmiku.tutorial.service.PostService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
@Service @Service
public class PostServiceImpl extends ServiceImpl<PostMapper, Post> implements PostService { public class PostServiceImpl extends ServiceImpl<PostMapper, Post> implements PostService {
@@ -32,13 +23,6 @@ public class PostServiceImpl extends ServiceImpl<PostMapper, Post> implements Po
@Autowired @Autowired
private PostMapper postMapper; private PostMapper postMapper;
@Lazy
@Autowired
private InteractionService interactionService;
@Autowired
private BrowingHistoryService browingHistoryService;
@Override @Override
public void createPost(Post post) { public void createPost(Post post) {
logger.info("开始创建帖子"); logger.info("开始创建帖子");
@@ -50,24 +34,15 @@ public class PostServiceImpl extends ServiceImpl<PostMapper, Post> implements Po
} }
@Override @Override
public Post getPostById(Long postId, String userOpenid) { public Post getPostById(Long postId) {
logger.info("用户openid{} 开始根据ID获取帖子详情帖子ID{}", userOpenid, postId); logger.info("开始根据ID获取帖子详情帖子ID{}", postId);
LambdaQueryWrapper<Post> wrapper = new LambdaQueryWrapper<>();
// 查找帖子信息 wrapper.eq(Post::getIsPublic, 1);
Post post = postMapper.selectById(postId); Post post = postMapper.selectById(wrapper);
if (post == null || post.getIsDeleted() == 1) { if (post == null) {
logger.warn("帖子ID{}不存在或已删除", postId); logger.warn("帖子ID{}不存在", postId);
return null; return null;
} }
// 创建浏览记录
BrowingHistory browingHistory = new BrowingHistory();
browingHistory.setUserOpenid(userOpenid);
browingHistory.setPostId(postId);
browingHistory.setCreateAt(new Date());
browingHistory.setIsDelete(0); // 未删除标记
browingHistoryService.save(browingHistory);
logger.info("用户openid{}的浏览记录创建成功", userOpenid);
return post; return post;
} }
@@ -95,83 +70,83 @@ public class PostServiceImpl extends ServiceImpl<PostMapper, Post> implements Po
} }
@Override @Override
public IPage<Post> getPostList(String userId, int pageNum, int pageSize) { public PageInfo<Post> getPostList(String userId, int pageNum, int pageSize) {
logger.info("用户ID{}开始获取帖子列表,第{}页,每页{}条", userId, pageNum, pageSize); logger.info("用户ID{}开始获取帖子列表,第{}页,每页{}条", userId, pageNum, pageSize);
// 设置分页参数 // 设置分页参数
// PageHelper.startPage(pageNum, pageSize); PageHelper.startPage(pageNum, pageSize);
IPage<Post> page = new Page<>(pageNum, pageSize);
LambdaQueryWrapper<Post> wrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<Post> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Post::getUserOpenid, userId); wrapper.eq(Post::getUserOpenid, userId);
wrapper.eq(Post::getIsDeleted, 0); wrapper.eq(Post::getIsDeleted, 0);
wrapper.eq(Post::getIsPublic, 1); wrapper.eq(Post::getIsPublic, 1);
IPage<Post> posts = postMapper.selectPage(page, wrapper); List<Post> posts = postMapper.selectList(wrapper);
// 使用PageInfo封装分页结果 // 使用PageInfo封装分页结果
// PageInfo<Post> pageInfo = new PageInfo<>(posts); PageInfo<Post> pageInfo = new PageInfo<>(posts);
return posts; return pageInfo;
} }
@Override @Override
public IPage<Post> getCommunityPostList(Long communityId, int pageNum, int pageSize) { public PageInfo<Post> getCommunityPostList(Long communityId, int pageNum, int pageSize) {
logger.info("开始获取社区ID{}的帖子列表,第{}页,每页{}条", communityId, pageNum, pageSize); logger.info("开始获取社区ID{}的帖子列表,第{}页,每页{}条", communityId, pageNum, pageSize);
// 设置分页参数 // 设置分页参数
// PageHelper.startPage(pageNum, pageSize); PageHelper.startPage(pageNum, pageSize);
IPage<Post> page = new Page<>(pageNum, pageSize);
LambdaQueryWrapper<Post> wrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<Post> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Post::getCommunityId, communityId); wrapper.eq(Post::getCommunityId, communityId);
wrapper.eq(Post::getIsDeleted, 0); wrapper.eq(Post::getIsDeleted, 0);
wrapper.eq(Post::getIsPublic, 1); wrapper.eq(Post::getIsPublic, 1);
IPage<Post> posts = postMapper.selectPage(page, wrapper); List<Post> posts = postMapper.selectList(wrapper);
// 使用PageInfo封装分页结果 // 使用PageInfo封装分页结果
// PageInfo<Post> pageInfo = new PageInfo<>(posts); PageInfo<Post> pageInfo = new PageInfo<>(posts);
return posts; return pageInfo;
} }
@Override @Override
public IPage<Post> getOfficialPosts(int pageNum, int pageSize) { public PageInfo<Post> getOfficialPosts(int pageNum, int pageSize) {
logger.info("开始获取所有官方创建的帖子,第{}页,每页{}条", pageNum, pageSize); logger.info("开始获取所有官方创建的帖子,第{}页,每页{}条", pageNum, pageSize);
// 设置分页参数 // 设置分页参数
// PageHelper.startPage(pageNum, pageSize); PageHelper.startPage(pageNum, pageSize);
IPage<Post> page = new Page<>(pageNum, pageSize);
LambdaQueryWrapper<Post> wrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<Post> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Post::getIsOfficial, 1); wrapper.eq(Post::getIsOfficial, 1);
wrapper.eq(Post::getIsDeleted, 0); wrapper.eq(Post::getIsDeleted, 0);
wrapper.eq(Post::getIsPublic, 1); wrapper.eq(Post::getIsPublic, 1);
IPage<Post> posts = postMapper.selectPage(page, wrapper); List<Post> posts = postMapper.selectList(wrapper);
// 使用PageInfo封装分页结果 // 使用PageInfo封装分页结果
// PageInfo<Post> pageInfo = new PageInfo<>(posts); PageInfo<Post> pageInfo = new PageInfo<>(posts);
return posts; return pageInfo;
} }
@Override @Override
public IPage<Post> getNonOfficialPosts(int pageNum, int pageSize) { public PageInfo<Post> getNonOfficialPosts(int pageNum, int pageSize) {
logger.info("开始获取所有非官方创建的帖子,第{}页,每页{}条", pageNum, pageSize); logger.info("开始获取所有非官方创建的帖子,第{}页,每页{}条", pageNum, pageSize);
// 设置分页参数 // 设置分页参数
// PageHelper.startPage(pageNum, pageSize); PageHelper.startPage(pageNum, pageSize);
IPage<Post> page = new Page<>(pageNum, pageSize);
LambdaQueryWrapper<Post> wrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<Post> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Post::getIsOfficial, 0); wrapper.eq(Post::getIsOfficial, 0);
wrapper.eq(Post::getIsDeleted, 0); wrapper.eq(Post::getIsDeleted, 0);
wrapper.eq(Post::getIsPublic, 1); wrapper.eq(Post::getIsPublic, 1);
IPage<Post> posts = postMapper.selectPage(page, wrapper); List<Post> posts = postMapper.selectList(wrapper);
// 使用PageInfo封装分页结果 // 使用PageInfo封装分页结果
// PageInfo<Post> pageInfo = new PageInfo<>(posts); PageInfo<Post> pageInfo = new PageInfo<>(posts);
return posts; return pageInfo;
} }
@Override @Override
@@ -182,62 +157,4 @@ public class PostServiceImpl extends ServiceImpl<PostMapper, Post> implements Po
post.setIsPublic(isPublic); post.setIsPublic(isPublic);
postMapper.update(post, wrapper); postMapper.update(post, wrapper);
} }
@Override
public List<String> getPopularSearches() {
return postMapper.selectPopularSearches();
}
@Override
public List<Post> searchPosts(String keyword) {
// 调用 Mapper 中的搜索方法
return postMapper.searchPosts(keyword);
}
@Override
public List<Post> getTopFavoritedPosts(int limit) {
return postMapper.getTopFavoritedPosts(limit);
}
@Override
public List<Post> getDraftsByUserId(String userId) {
return postMapper.selectList(new LambdaQueryWrapper<Post>()
.eq(Post::getUserOpenid, userId)
.eq(Post::getIsDraft, 1)); // 0 表示草稿
}
@Override
public List<Post> getRecommendedPosts(Double latitude, Double longitude, List<String> searchHistory) {
// 1. 根据用户当前位置计算距离(例如使用 Haversine 公式)
List<Post> nearbyPosts = postMapper.getPostsNearby(latitude, longitude);
// 2. 根据帖子热度排序
List<Post> sortedPosts = sortPostsByHeat(nearbyPosts);
// 3. 根据用户的搜索历史关键词筛选相关帖子
List<Post> matchingPosts = sortedPosts.stream()
.filter(post -> searchHistory.stream().anyMatch(keyword ->
post.getTitle().contains(keyword) || post.getContent().contains(keyword)))
.collect(Collectors.toList());
return matchingPosts;
}
public List<Post> sortPostsByHeat(List<Post> posts) {
// 根据帖子热度进行排序
return posts.stream()
.sorted((post1, post2) -> {
int post1Heat = calculatePostHeat(post1);
int post2Heat = calculatePostHeat(post2);
return Integer.compare(post2Heat, post1Heat); // 降序排列
})
.collect(Collectors.toList());
}
public int calculatePostHeat(Post post) {
Long postId = post.getPostId();
return interactionService.getLikeCountByPostId(postId).intValue();
}
} }

View File

@@ -1,58 +0,0 @@
package com.ivmiku.tutorial.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ivmiku.tutorial.entity.Subscribe;
import com.ivmiku.tutorial.entity.Tag;
import com.ivmiku.tutorial.entity.User;
import com.ivmiku.tutorial.entity.UserDTO;
import com.ivmiku.tutorial.mapper.PostTagMapper;
import com.ivmiku.tutorial.mapper.SubscribeMapper;
import com.ivmiku.tutorial.mapper.TagMapper;
import com.ivmiku.tutorial.mapper.UserMapper;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
@Service
public class SearchService {
@Resource
private UserMapper userMapper;
@Resource
private TagMapper tagMapper;
@Resource
private SubscribeMapper subscribeMapper;
public List<UserDTO> getUserList(String text, String userId) {
int len = text.length();
QueryWrapper<Subscribe> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("user1_id", userId);
List<Subscribe> list = subscribeMapper.selectList(queryWrapper);
List<UserDTO> result = new ArrayList<>();
for (Subscribe subscribe : list) {
String user2Id = String.valueOf(subscribe.getSubId());
User user = userMapper.selectById(user2Id);
if (user.getNickname().substring(0, len).equals(text)) {
UserDTO userDTO = new UserDTO();
userDTO.setNickname(user.getNickname());
userDTO.setAvatarUrl(user.getAvatarUrl());
result.add(userDTO);
}
}
return result;
}
public List<String> getTag(String text) {
QueryWrapper<Tag> queryWrapper = new QueryWrapper<>();
queryWrapper.likeRight("name", text);
List<Tag> list = tagMapper.selectList(queryWrapper);
List<String> result = new ArrayList<>();
for (Tag tag : list) {
result.add(tag.getName());
}
return result;
}
}

View File

@@ -1,56 +0,0 @@
package com.ivmiku.tutorial.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ivmiku.tutorial.entity.TutorialTags;
import com.ivmiku.tutorial.service.TutorialTagsService;
import com.ivmiku.tutorial.mapper.TutorialTagsMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @author rog
* @description 针对表【tutorial_tags】的数据库操作Service实现
* @createDate 2024-08-29 21:15:08
*/
@Service
public class TutorialTagsServiceImpl extends ServiceImpl<TutorialTagsMapper, TutorialTags>
implements TutorialTagsService{
@Autowired
private TutorialTagsMapper tutorialTagsMapper;
@Override
public void createTag(TutorialTags tag) {
tutorialTagsMapper.insert(tag);
}
@Override
public List<TutorialTags> getAllTags() {
QueryWrapper<TutorialTags> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("is_deleted", 0);
return tutorialTagsMapper.selectList(queryWrapper);
}
@Override
public TutorialTags getTagById(Long tagId) {
return tutorialTagsMapper.selectById(tagId);
}
@Override
public void updateTag(TutorialTags tag) {
tutorialTagsMapper.updateById(tag);
}
@Override
public void deleteTag(Long tagId) {
tutorialTagsMapper.deleteById(tagId);
}
}

View File

@@ -1,53 +0,0 @@
package com.ivmiku.tutorial.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ivmiku.tutorial.entity.Tutorials;
import com.ivmiku.tutorial.service.TutorialsService;
import com.ivmiku.tutorial.mapper.TutorialsMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @author rog
* @description 针对表【tutorials】的数据库操作Service实现
* @createDate 2024-08-29 21:14:50
*/
@Service
public class TutorialsServiceImpl extends ServiceImpl<TutorialsMapper, Tutorials>
implements TutorialsService{
@Autowired
private TutorialsMapper tutorialsMapper;
// 其他已存在的方法
@Override
public List<Tutorials> getTutorialsByTagId(Long tagId) {
QueryWrapper<Tutorials> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("tag_id", tagId);
return tutorialsMapper.selectList(queryWrapper);
}
@Override
public List<Tutorials> getTutorialsByIds(List<Long> tutorialIds) {
if (tutorialIds != null && !tutorialIds.isEmpty()) {
QueryWrapper<Tutorials> queryWrapper = new QueryWrapper<>();
queryWrapper.in("tutorial_id", tutorialIds);
return tutorialsMapper.selectList(queryWrapper);
}
return null;
}
@Override
public void createTutorial(Tutorials tutorial) {
this.save(tutorial);
}
}

View File

@@ -1,94 +0,0 @@
package com.ivmiku.tutorial.util;
import com.alibaba.fastjson2.JSON;
import com.ivmiku.tutorial.response.AtNotifier;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* @author Aurora
*/
@Component
public class MyRedisUtil {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
public void listAdd(String key, Object value) {
redisTemplate.opsForList().leftPush(key, value);
}
public List<AtNotifier> listGet(String key, int s, int e) {
List<Object> list = redisTemplate.opsForList().range(key, s, e);
List<AtNotifier> result = new ArrayList<>();
if (list != null) {
for (Object json : list) {
result.add(JSON.parseObject(JSON.toJSONString(json), AtNotifier.class));
}
}
return result;
}
public void listClear(String key) {
redisTemplate.opsForList().trim(key, 1, 0);
}
public Long getListSize(String key) {
return redisTemplate.opsForList().size(key);
}
public Set<String> getKey() {
return redisTemplate.keys("history:*");
}
public Object rightPop(String key) {
return redisTemplate.opsForList().rightPop(key);
}
public void setExpireTime(String key) {
if (redisTemplate.opsForValue().getOperations().getExpire(key) > 0) {
redisTemplate.expire(key, 3, TimeUnit.DAYS);
}
}
public void refreshExpire(String key) {
redisTemplate.persist(key);
redisTemplate.expire(key, 3, TimeUnit.DAYS);
}
public boolean ifExist(String key) {
return Boolean.TRUE.equals(redisTemplate.hasKey(key));
}
public List<String> getStringList(String key, int s, int e) {
List<Object> list = redisTemplate.opsForList().range(key, s, e);
List<String> result = new ArrayList<>();
assert list != null;
for (Object object : list) {
result.add((String) object);
}
return result;
}
public void insertKey(String openid, String sessionKey) {
redisTemplate.opsForValue().set("sessionkey:" + openid, sessionKey);
}
public String getKey(String userId) {
return (String) redisTemplate.opsForValue().get("sessionkey:" + userId);
}
public void deleteFromList(AtNotifier message) {
String id = message.getToId();
redisTemplate.opsForList().remove("unread:" + id, 0, message);
}
}

View File

@@ -1,11 +1,9 @@
wx.miniapp.configs[0].appid=wx0d4fdb5c7bf3b12b wx.miniapp.configs[0].appid=wx0d4fdb5c7bf3b12b
wx.miniapp.configs[0].secret=989f155fcc3aee616568473faf1b1d3b 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.port=6379
spring.data.redis.database=0 spring.data.redis.database=0
spring.data.redis.password=Shuodedaoli114514
spring.application.name=community spring.application.name=community
@@ -13,25 +11,14 @@ server.port=8073
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root spring.datasource.username=root
spring.datasource.password=Shuodedaoli114514 spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://mysql:3306/tutorial?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true 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 spring.cloud.nacos.discovery.enabled=true
dubbo.application.qos-enable=false management.zipkin.tracing.endpoint=http://127.0.0.1:9411/api/v2/spans
management.tracing.sampling.probability=1.0
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
spring.data.redis.lettuce.pool.max-active=32
spring.data.redis.lettuce.pool.max-idle=16
spring.data.redis.lettuce.pool.min-idle=8
spring.rabbitmq.host=rabbitmq

View File

@@ -27,7 +27,3 @@ minio.accessKey=minio_root
minio.secretKey=minio_123456 minio.secretKey=minio_123456
minio.bucketName=haixia minio.bucketName=haixia
## Nacos??
#spring.cloud.nacos.discovery.server-addr=/192.168.146.1:8848
#dubbo.registry.address=nacos:///192.168.146.1:8848

View File

@@ -1,19 +0,0 @@
<?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.BrowingHistoryMapper">
<resultMap id="BaseResultMap" type="com.ivmiku.tutorial.entity.BrowingHistory">
<id property="browingId" column="browing_id" jdbcType="BIGINT"/>
<result property="userOpenid" column="user_openid" jdbcType="VARCHAR"/>
<result property="postId" column="post_id" jdbcType="BIGINT"/>
<result property="createAt" column="create_at" jdbcType="TIMESTAMP"/>
<result property="isDelete" column="is_delete" jdbcType="TINYINT"/>
</resultMap>
<sql id="Base_Column_List">
browing_id,user_openid,post_id,
create_at,is_delete
</sql>
</mapper>

View File

@@ -8,7 +8,6 @@
<id property="commentId" column="comment_id" jdbcType="BIGINT"/> <id property="commentId" column="comment_id" jdbcType="BIGINT"/>
<result property="userOpenid" column="user_openid" jdbcType="VARCHAR"/> <result property="userOpenid" column="user_openid" jdbcType="VARCHAR"/>
<result property="postId" column="post_id" jdbcType="BIGINT"/> <result property="postId" column="post_id" jdbcType="BIGINT"/>
<result property="tutorialId" column="tutorialId" jdbcType="BIGINT"/>
<result property="content" column="content" jdbcType="VARCHAR"/> <result property="content" column="content" jdbcType="VARCHAR"/>
<result property="parentCommentId" column="parent_comment_id" jdbcType="BIGINT"/> <result property="parentCommentId" column="parent_comment_id" jdbcType="BIGINT"/>
<result property="isDeleted" column="is_deleted" jdbcType="TINYINT"/> <result property="isDeleted" column="is_deleted" jdbcType="TINYINT"/>
@@ -20,7 +19,7 @@
</resultMap> </resultMap>
<sql id="Base_Column_List"> <sql id="Base_Column_List">
comment_id, user_openid, post_id, tutorialId, content, comment_id, user_openid, post_id, content,
parent_comment_id, is_deleted, created_at, updated_at, parent_comment_id, is_deleted, created_at, updated_at,
mentioned_user_id, image_urls, video_url mentioned_user_id, image_urls, video_url
</sql> </sql>

View File

@@ -1,18 +0,0 @@
<?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.CommunitytagMapper">
<resultMap id="BaseResultMap" type="com.ivmiku.tutorial.entity.Communitytag">
<id property="smallCTagId" column="small_c_tag_id" jdbcType="BIGINT"/>
<result property="cTagName" column="c_tag_name" jdbcType="VARCHAR"/>
<result property="cId" column="c_id" jdbcType="BIGINT"/>
<result property="isDelete" column="is_delete" jdbcType="TINYINT"/>
</resultMap>
<sql id="Base_Column_List">
small_c_tag_id,c_tag_name,c_id,
is_delete
</sql>
</mapper>

View File

@@ -8,12 +8,11 @@
<id property="id" column="id" jdbcType="BIGINT"/> <id property="id" column="id" jdbcType="BIGINT"/>
<result property="userOpenid" column="user_openid" jdbcType="VARCHAR"/> <result property="userOpenid" column="user_openid" jdbcType="VARCHAR"/>
<result property="postId" column="post_id" jdbcType="BIGINT"/> <result property="postId" column="post_id" jdbcType="BIGINT"/>
<result property="tutorialId" column="tutorialId" jdbcType="BIGINT"/>
<result property="isDeleted" column="is_deleted" jdbcType="TINYINT"/> <result property="isDeleted" column="is_deleted" jdbcType="TINYINT"/>
</resultMap> </resultMap>
<sql id="Base_Column_List"> <sql id="Base_Column_List">
id,user_openid, post_id, tutorialId, id,user_openid,post_id,
is_deleted is_deleted
</sql> </sql>
</mapper> </mapper>

View File

@@ -5,33 +5,15 @@
<mapper namespace="com.ivmiku.tutorial.mapper.LikeMapper"> <mapper namespace="com.ivmiku.tutorial.mapper.LikeMapper">
<resultMap id="BaseResultMap" type="com.ivmiku.tutorial.entity.Likee"> <resultMap id="BaseResultMap" type="com.ivmiku.tutorial.entity.Likee">
<id property="id" column="id" jdbcType="BIGINT"/> <id property="id" column="id" jdbcType="BIGINT"/>
<result property="userOpenid" column="user_openid" jdbcType="VARCHAR"/> <result property="userOpenid" column="user_openid" jdbcType="VARCHAR"/>
<result property="postId" column="post_id" jdbcType="BIGINT"/> <result property="postId" column="post_id" jdbcType="BIGINT"/>
<result property="tutorialId" column="tutorial_id" jdbcType="BIGINT"/> <result property="commentId" column="comment_id" jdbcType="BIGINT"/>
<result property="commentId" column="comment_id" jdbcType="BIGINT"/> <result property="isDeleted" column="is_deleted" jdbcType="TINYINT"/>
<result property="isDeleted" column="is_deleted" jdbcType="TINYINT"/>
</resultMap> </resultMap>
<sql id="Base_Column_List"> <sql id="Base_Column_List">
id, user_openid, post_id, tutorial_id, comment_id, is_deleted id,user_openid,post_id,
comment_id,is_deleted
</sql> </sql>
<!-- 查询用户所有帖子的点赞总数 -->
<select id="getPostLikeCount" resultType="java.lang.Long">
SELECT COUNT(*)
FROM likee
WHERE user_openid = #{userOpenid}
AND post_id IS NOT NULL
AND is_deleted = 0;
</select>
<!-- 查询用户所有评论的点赞总数 -->
<select id="getCommentLikeCount" resultType="java.lang.Long">
SELECT COUNT(*)
FROM likee
WHERE user_openid = #{userOpenid}
AND comment_id IS NOT NULL
AND is_deleted = 0;
</select>
</mapper> </mapper>

View File

@@ -16,7 +16,6 @@
<result property="isOfficial" column="is_official" jdbcType="TINYINT"/> <result property="isOfficial" column="is_official" jdbcType="TINYINT"/>
<result property="isPublic" column="is_public" jdbcType="TINYINT"/> <result property="isPublic" column="is_public" jdbcType="TINYINT"/>
<result property="location" column="location" jdbcType="VARCHAR"/> <result property="location" column="location" jdbcType="VARCHAR"/>
<result property="isDraft" column="is_draft" jdbcType="TINYINT"/>
<result property="createdAt" column="created_at" jdbcType="TIMESTAMP"/> <result property="createdAt" column="created_at" jdbcType="TIMESTAMP"/>
<result property="updatedAt" column="updated_at" jdbcType="TIMESTAMP"/> <result property="updatedAt" column="updated_at" jdbcType="TIMESTAMP"/>
</resultMap> </resultMap>
@@ -38,33 +37,32 @@
<!-- 插入新的帖子 --> <!-- 插入新的帖子 -->
<insert id="insertPost" parameterType="com.ivmiku.tutorial.entity.Post"> <insert id="insertPost" parameterType="com.ivmiku.tutorial.entity.Post">
INSERT INTO post ( INSERT INTO post (
post_id, user_openid, community_id, title, content, post_id, user_openid, community_id, title, content,
video_url, image_urls, video_url, image_urls,
is_deleted, is_official, is_public, location, is_draft, created_at, updated_at is_deleted, is_official, is_public, location, created_at, updated_at
) VALUES ( ) VALUES (
#{postId}, #{userOpenid}, #{communityId}, #{title}, #{content}, #{postId}, #{userOpenid}, #{communityId}, #{title}, #{content},
#{videoUrl}, #{imageUrls}, #{videoUrl}, #{imageUrls},
#{isDeleted}, #{isOfficial}, #{isPublic}, #{location}, #{isDraft}, #{createdAt}, #{updatedAt} #{isDeleted}, #{isOfficial}, #{is_public}, #{location}, #{createdAt}, #{updatedAt}
) )
</insert> </insert>
<!-- 更新帖子 --> <!-- 更新帖子 -->
<update id="updatePost" parameterType="com.ivmiku.tutorial.entity.Post"> <update id="updatePost" parameterType="com.ivmiku.tutorial.entity.Post">
UPDATE post UPDATE post
SET SET
user_openid = #{userOpenid}, user_openid = #{userOpenid},
community_id = #{communityId}, community_id = #{communityId},
title = #{title}, title = #{title},
content = #{content}, content = #{content},
video_url = #{videoUrl}, video_url = #{videoUrl},
image_urls = #{imageUrls}, image_urls = #{imageUrls},
is_deleted = #{isDeleted}, is_deleted = #{isDeleted},
is_official = #{isOfficial}, is_official = #{isOfficial},
is_public = #{isPublic}, is_public = #{is_public},
location = #{location}, location = #{location},
is_draft = #{isDraft}, created_at = #{createdAt},
created_at = #{createdAt}, updated_at = #{updatedAt}
updated_at = #{updatedAt}
WHERE post_id = #{postId} WHERE post_id = #{postId}
</update> </update>
@@ -82,36 +80,5 @@
FROM post p, posttag pt, tag t 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 AND p.is_public = 1 WHERE p.post_id = pt.post_id AND pt.tag_id = t.tag_id AND t.tag_id = #{tagId} AND p.is_deleted = 0 AND p.is_public = 1
</select> </select>
<select id="selectPopularSearches" resultType="java.lang.String">
SELECT title
FROM post
WHERE is_deleted = 0 AND is_public = 1
LIMIT 9
</select>
<select id="searchPosts" resultType="com.ivmiku.tutorial.entity.Post">
SELECT
<include refid="Base_Column_List"/>
FROM post
WHERE is_deleted = 0
AND is_public = 1
AND (title LIKE CONCAT('%', #{keyword}, '%')
OR content LIKE CONCAT('%', #{keyword}, '%'))
</select>
<select id="getTopFavoritedPosts" 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.is_public, p.location, p.created_at, p.updated_at
FROM post p
JOIN favorite f ON p.post_id = f.post_id
WHERE p.is_deleted = 0 AND p.is_public = 1 AND f.is_deleted = 0
GROUP BY p.post_id
ORDER BY COUNT(f.id) DESC
LIMIT #{limit}
</select>
<select id="getPostsBasedOnHistoryAndHotness" resultType="com.ivmiku.tutorial.entity.Post">
SELECT *
FROM post
WHERE content LIKE CONCAT('%', #{searchHistory}, '%')
ORDER BY hotness DESC
</select>
</mapper> </mapper>

View File

@@ -1,18 +0,0 @@
<?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.TutorialTagsMapper">
<resultMap id="BaseResultMap" type="com.ivmiku.tutorial.entity.TutorialTags">
<id property="tagId" column="tag_id" jdbcType="BIGINT"/>
<result property="tagName" column="tag_name" jdbcType="VARCHAR"/>
<result property="isOfficial" column="is_official" jdbcType="TINYINT"/>
<result property="isDeleted" column="is_deleted" jdbcType="TINYINT"/>
</resultMap>
<sql id="Base_Column_List">
tag_id,tag_name,is_official,
is_deleted
</sql>
</mapper>

View File

@@ -1,26 +0,0 @@
<?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.TutorialsMapper">
<resultMap id="BaseResultMap" type="com.ivmiku.tutorial.entity.Tutorials">
<id column="tutorial_id" property="tutorialId" jdbcType="BIGINT"/>
<result column="title" property="title" jdbcType="VARCHAR"/>
<result column="content" property="content" jdbcType="VARCHAR"/>
<result column="image_url" property="imageUrl" jdbcType="VARCHAR"/>
<result column="video_url" property="videoUrl" jdbcType="VARCHAR"/>
<result column="is_official" property="isOfficial" jdbcType="INTEGER"/>
<result column="is_deleted" property="isDeleted" jdbcType="INTEGER"/>
<result column="created_at" property="createdAt" jdbcType="TIMESTAMP"/>
<result column="tag_id" property="tagId" jdbcType="BIGINT"/>
<result column="user_openid" property="userOpenid" jdbcType="VARCHAR"/> <!-- 新增的映射 -->
</resultMap>
<sql id="Base_Column_List">
tutorial_id,title,content,
image_url,video_url,is_official,
is_deleted,created_at,tag_id
</sql>
</mapper>

View File

@@ -56,6 +56,26 @@
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId> <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency> </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> <dependency>
<groupId>com.alibaba.csp</groupId> <groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId> <artifactId>sentinel-transport-simple-http</artifactId>

View File

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

View File

@@ -47,8 +47,7 @@ public class SaTokenConfigure {
"/user/register", "/user/register",
"/swagger-resources/**", "/swagger-resources/**",
"/v3/**", "/v3/**",
"/swagger-ui/**", "/swagger-ui/**")
"/ws/**")
// 鉴权方法:每次访问进入 // 鉴权方法:每次访问进入
.setAuth(obj -> { .setAuth(obj -> {
// 登录校验 -- 拦截所有路由,并排除指定路由 // 登录校验 -- 拦截所有路由,并排除指定路由

View File

@@ -1,32 +1,16 @@
server.port=8133 server.port=8133
spring.application.name=gateway 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.port=6379
spring.data.redis.database=0 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].id=user
spring.cloud.gateway.routes[0].uri=lb://user spring.cloud.gateway.routes[0].uri=lb://user
spring.cloud.gateway.routes[0].predicates[0]=Path=/user/** spring.cloud.gateway.routes[0].predicates[0]=Path=/user/**
spring.cloud.gateway.routes[0].filters[0]=StripPrefix=1
spring.cloud.gateway.routes[1].id=community management.zipkin.tracing.endpoint=http://127.0.0.1:9411/api/v2/spans
spring.cloud.gateway.routes[1].uri=lb://community management.tracing.sampling.probability=1.0
spring.cloud.gateway.routes[1].predicates[0]=Path=/community/**
spring.cloud.gateway.routes[1].filters[0]=StripPrefix=1
spring.cloud.gateway.routes[2].id=navigate
spring.cloud.gateway.routes[2].uri=lb://navigate
spring.cloud.gateway.routes[2].predicates[0]=Path=/navigate/**
spring.cloud.gateway.routes[2].filters[0]=StripPrefix=1
spring.cloud.gateway.routes[3].id=websocket
spring.cloud.gateway.routes[3].uri=lb:ws://user
spring.cloud.gateway.routes[3].predicates[0]=Path=/chat/**
spring.cloud.gateway.routes[4].id=search
spring.cloud.gateway.routes[4].uri=lb:ws://community
spring.cloud.gateway.routes[4].predicates[0]=Path=/search/**

View File

@@ -17,15 +17,5 @@ spring.cloud.gateway.routes[1].uri=lb://community
spring.cloud.gateway.routes[1].predicates[0]=Path=/community/** spring.cloud.gateway.routes[1].predicates[0]=Path=/community/**
spring.cloud.gateway.routes[1].filters[0]=StripPrefix=1 spring.cloud.gateway.routes[1].filters[0]=StripPrefix=1
spring.cloud.gateway.routes[2].id=navigate #management.zipkin.tracing.endpoint=http://localhost:9411/api/v2/spans
spring.cloud.gateway.routes[2].uri=lb://navigate #management.tracing.sampling.probability=1.0
spring.cloud.gateway.routes[2].predicates[0]=Path=/navigate/**
spring.cloud.gateway.routes[2].filters[0]=StripPrefix=1
spring.cloud.gateway.routes[3].id=websocket
spring.cloud.gateway.routes[3].uri=lb:ws://user
spring.cloud.gateway.routes[3].predicates[0]=Path=/chat/**
spring.cloud.gateway.routes[4].id=search
spring.cloud.gateway.routes[4].uri=lb:ws://community
spring.cloud.gateway.routes[4].predicates[0]=Path=/search/**

Binary file not shown.

View File

@@ -29,7 +29,6 @@
<dependency> <dependency>
<groupId>com.baomidou</groupId> <groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId> <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>3.5.7</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.alibaba.cloud</groupId> <groupId>com.alibaba.cloud</groupId>
@@ -38,7 +37,7 @@
<dependency> <dependency>
<groupId>com.mysql</groupId> <groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId> <artifactId>mysql-connector-j</artifactId>
<version>8.2.0</version> <scope>runtime</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
@@ -104,56 +103,5 @@
<artifactId>tencentcloud-sdk-java-tts</artifactId> <artifactId>tencentcloud-sdk-java-tts</artifactId>
<version>3.1.1076</version> <version>3.1.1076</version>
</dependency> </dependency>
<dependency>
<groupId>com.tencentcloudapi</groupId>
<artifactId>tencentcloud-sdk-java-asr</artifactId>
<version>3.1.1083</version>
</dependency>
<!-- https://mvnrepository.com/artifact/ai.djl/api -->
<dependency>
<groupId>ai.djl</groupId>
<artifactId>api</artifactId>
<version>0.29.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/ai.djl.pytorch/pytorch-model-zoo -->
<dependency>
<groupId>ai.djl.pytorch</groupId>
<artifactId>pytorch-model-zoo</artifactId>
<version>0.29.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/ai.djl.pytorch/pytorch-engine -->
<dependency>
<groupId>ai.djl.pytorch</groupId>
<artifactId>pytorch-engine</artifactId>
<version>0.29.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/ai.djl.pytorch/pytorch-native-auto -->
<dependency>
<groupId>ai.djl.pytorch</groupId>
<artifactId>pytorch-native-auto</artifactId>
<version>1.9.1</version>
<scope>runtime</scope>
</dependency>
</dependencies> </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.Main8432</mainClass>
<layout>JAR</layout>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project> </project>

View File

@@ -1,15 +1,12 @@
package com.ivmiku.tutorial.controller; package com.ivmiku.tutorial.controller;
import cn.dev33.satoken.annotation.SaCheckLogin; import cn.dev33.satoken.annotation.SaCheckLogin;
import com.ivmiku.tutorial.entity.AssistantQuery;
import com.ivmiku.tutorial.response.Result; import com.ivmiku.tutorial.response.Result;
import com.ivmiku.tutorial.service.AssistantService; import com.ivmiku.tutorial.service.AssistantService;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
@RestController @RestController
@@ -19,13 +16,19 @@ public class AssistantController {
@Resource @Resource
private AssistantService assistantService; private AssistantService assistantService;
@PostMapping("/response") @GetMapping("/response")
public Object getResponse(@RequestBody AssistantQuery query) { public Object getResponse(@RequestParam String input) {
String userInput = assistantService.speechRecognition(query.getContent(), query.getSize(), query.getLanguage()); Map<String, Object> map = assistantService.getResponse(input);
Map<String, Object> map = assistantService.getResponse(userInput, query.getLanguage());
if (map == null) { if (map == null) {
return Result.error("请求出错"); return Result.error("请求出错");
} }
return Result.ok(map); return Result.ok(map);
} }
@GetMapping("/tts")
public Object textToSpeech(@RequestParam String input) {
Map<String, Object> map = new HashMap<>();
map.put("content", assistantService.textToSpeech(input));
return Result.ok(map);
}
} }

View File

@@ -57,29 +57,10 @@ public class NavigateController {
} }
@PostMapping("/ticket") @PostMapping("/ticket")
public Object scanTicket(@RequestPart MultipartFile file, @RequestParam String location) throws IOException { public Object scanTicket(@RequestPart MultipartFile file) throws IOException {
BufferedImage image = ImageIO.read(file.getInputStream()); BufferedImage image = ImageIO.read(file.getInputStream());
Map<String, Object> map = navigateService.scanTicket(image); Map<String, Object> map = navigateService.scanTicket(image);
Map<String, Object> result = new HashMap<>(); return Result.ok(map);
if (map.containsKey("登机口")) {
String address = navigateService.deGeoCode(location);
address += map.get("登机口");
address += "登机口";
result.put("地址", address);
} else if (map.containsKey("检票口")) {
if (map.containsKey("左边车站")) {
String address = (String) map.get("左边车站");
address += map.get("检票口");
address += "检票口";
result.put("地址", address);
} else {
String address = navigateService.deGeoCode(location);
address += map.get("检票口");
address += "检票口";
result.put("地址", address);
}
}
return Result.ok(result);
} }
@GetMapping("/geocode") @GetMapping("/geocode")

View File

@@ -1,10 +0,0 @@
package com.ivmiku.tutorial.entity;
import lombok.Data;
@Data
public class AssistantQuery {
private String content;
private Integer size;
private String language;
}

View File

@@ -1,14 +0,0 @@
package com.ivmiku.tutorial.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@TableName("guidance")
@Data
public class Guidance {
@TableId
private String id;
private String tag;
private String content;
}

View File

@@ -1,8 +0,0 @@
package com.ivmiku.tutorial.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ivmiku.tutorial.entity.Guidance;
public interface GuidanceMapper extends BaseMapper<Guidance> {
}

View File

@@ -2,15 +2,11 @@ package com.ivmiku.tutorial.service;
import cn.hutool.http.HttpRequest; import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse; import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ivmiku.tutorial.entity.Guidance;
import com.ivmiku.tutorial.mapper.GuidanceMapper;
import com.ivmiku.tutorial.utils.SnowflakeUtil; import com.ivmiku.tutorial.utils.SnowflakeUtil;
import com.tencentcloudapi.asr.v20190614.AsrClient; import com.tencentcloudapi.common.AbstractModel;
import com.tencentcloudapi.asr.v20190614.models.SentenceRecognitionRequest;
import com.tencentcloudapi.asr.v20190614.models.SentenceRecognitionResponse;
import com.tencentcloudapi.common.Credential; import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException; import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile; import com.tencentcloudapi.common.profile.ClientProfile;
@@ -18,32 +14,21 @@ import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.tts.v20190823.TtsClient; import com.tencentcloudapi.tts.v20190823.TtsClient;
import com.tencentcloudapi.tts.v20190823.models.TextToVoiceRequest; import com.tencentcloudapi.tts.v20190823.models.TextToVoiceRequest;
import com.tencentcloudapi.tts.v20190823.models.TextToVoiceResponse; import com.tencentcloudapi.tts.v20190823.models.TextToVoiceResponse;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
@Service @Service
public class AssistantService { public class AssistantService {
@Resource
private GuidanceMapper guidanceMapper;
private final String auth = "bad1f6cad39a4c26aa9fe9e4324e096f:ZDczMDIwOTg3NjlhODdmYWVjYTY0YjM1"; private final String auth = "bad1f6cad39a4c26aa9fe9e4324e096f:ZDczMDIwOTg3NjlhODdmYWVjYTY0YjM1";
private final String secretId = "AKID09INNYxYEFFJH3g9VhljVF3qbDiFdx50"; private final String secretId = "AKID09INNYxYEFFJH3g9VhljVF3qbDiFdx50";
private final String secretKey = "KajjcNyNaaUCqQroqpzNoMtTHNj4Lbil"; private final String secretKey = "KajjcNyNaaUCqQroqpzNoMtTHNj4Lbil";
public String getAiResponse(String userInput, String language) { public Map<String, Object> getResponse(String userInput) {
Map<String, Object> message1 = new HashMap<>(); Map<String, Object> message1 = new HashMap<>();
message1.put("role", "system"); message1.put("role", "system");
String prompt = "模仿语音助手,对用户的问题给出简短的回答"; message1.put("content", "模仿语音助手,对用户的问题给出简短的回答");
if ("Chinese".equals(language)) {
prompt += ",用中文回答";
} else if ("English".equals(language)) {
prompt += ",用英文回答";
}
message1.put("content", prompt);
Map<String, Object> message2 = new HashMap<>(); Map<String, Object> message2 = new HashMap<>();
message2.put("role", "user"); message2.put("role", "user");
message2.put("content", userInput); message2.put("content", userInput);
@@ -66,10 +51,12 @@ public class AssistantService {
JSONArray choices = result.getJSONArray("choices"); JSONArray choices = result.getJSONArray("choices");
JSONObject message = choices.getJSONObject(0); JSONObject message = choices.getJSONObject(0);
JSONObject content = message.getJSONObject("message"); JSONObject content = message.getJSONObject("message");
return content.getString("content"); Map<String, Object> map = new HashMap<>();
map.put("content", content.get("content"));
return map;
} }
public String textToSpeech(String content, String language) { public String textToSpeech(String content) {
try{ try{
Credential cred = new Credential(secretId, secretKey); Credential cred = new Credential(secretId, secretKey);
HttpProfile httpProfile = new HttpProfile(); HttpProfile httpProfile = new HttpProfile();
@@ -81,89 +68,10 @@ public class AssistantService {
req.setText(content); req.setText(content);
req.setSessionId(SnowflakeUtil.getNext()); req.setSessionId(SnowflakeUtil.getNext());
req.setVoiceType(101006L); req.setVoiceType(101006L);
if (language.equals("English")) {
req.setPrimaryLanguage(2L);
}
TextToVoiceResponse resp = client.TextToVoice(req); TextToVoiceResponse resp = client.TextToVoice(req);
return resp.getAudio(); return resp.getAudio();
} catch (TencentCloudSDKException e) { } catch (TencentCloudSDKException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
public String speechRecognition(String content, Integer length, String language) {
try{
Credential cred = new Credential(secretId, secretKey);
HttpProfile httpProfile = new HttpProfile();
httpProfile.setEndpoint("asr.tencentcloudapi.com");
ClientProfile clientProfile = new ClientProfile();
clientProfile.setHttpProfile(httpProfile);
AsrClient client = new AsrClient(cred, "", clientProfile);
SentenceRecognitionRequest req = new SentenceRecognitionRequest();
if ("Chinese".equals(language)) {
req.setEngSerViceType("16k_zh");
} else if ("English".equals(language)) {
req.setEngSerViceType("16k_en");
}
req.setSourceType(1L);
req.setVoiceFormat("wav");
req.setData(content);
req.setDataLen(Long.valueOf(length));
SentenceRecognitionResponse resp = client.SentenceRecognition(req);
return resp.getResult();
} catch (TencentCloudSDKException e) {
throw new RuntimeException(e);
}
}
public String searchGuidance(String tag) {
QueryWrapper<Guidance> queryWrapper = new QueryWrapper<>();
queryWrapper.like("tag", tag);
List<Guidance> list = guidanceMapper.selectList(queryWrapper);
if (list.isEmpty()) {
return null;
}
return list.getFirst().getContent();
}
public String extractTag(String query) {
Map<String, Object> message1 = new HashMap<>();
message1.put("role", "system");
message1.put("content", "根据给出的句子的意思,从以下标签中返回最匹配的一个:安全带、安检、飞机");
Map<String, Object> message2 = new HashMap<>();
message2.put("role", "user");
message2.put("content", query);
JSONArray array = new JSONArray();
array.add(message1);
array.add(message2);
JSONObject params = new JSONObject();
params.put("model", "general");
params.put("messages", array);
HttpResponse response = HttpRequest.post("https://spark-api-open.xf-yun.com/v1/chat/completions")
.header("Content-Type", "application/json")
.header("Authorization", "Bearer " + auth)
.body(params.toJSONString())
.execute();
JSONObject result = JSONObject.parseObject(response.body());
response.close();
if (result.getInteger("code") != 0) {
return null;
}
JSONArray choices = result.getJSONArray("choices");
JSONObject message = choices.getJSONObject(0);
return String.valueOf(message.getJSONObject("message"));
}
public Map<String, Object> getResponse(String query, String language) {
Map<String, Object> result = new HashMap<>();
String tag = extractTag(query);
String content;
content = searchGuidance(tag);
if (content == null) {
content = getAiResponse(query, language);
}
Map<String, Object> map = new HashMap<>();
map.put("content", textToSpeech(content, language));
return map;
}
} }

View File

@@ -53,7 +53,7 @@ public class NavigateService {
} }
public Map<String, Object> scanTicket(BufferedImage image) { public Map<String, Object> scanTicket(BufferedImage image) {
String base64Img = ImgUtil.toBase64(image, "png"); String base64Img = ImgUtil.toBase64(image, "jpg");
SmartStructuralOCRV2Response resp; SmartStructuralOCRV2Response resp;
try { try {
Credential cred = new Credential(secretId, secretKey); Credential cred = new Credential(secretId, secretKey);
@@ -64,7 +64,7 @@ public class NavigateService {
OcrClient client = new OcrClient(cred, "ap-shanghai", clientProfile); OcrClient client = new OcrClient(cred, "ap-shanghai", clientProfile);
SmartStructuralOCRV2Request req = new SmartStructuralOCRV2Request(); SmartStructuralOCRV2Request req = new SmartStructuralOCRV2Request();
req.setImageBase64(base64Img); req.setImageBase64(base64Img);
String[] itemNames1 = {"登机口", "检票口", "左边车站", "右边车站"}; String[] itemNames1 = {"登机口", "检票口"};
req.setItemNames(itemNames1); req.setItemNames(itemNames1);
resp = client.SmartStructuralOCRV2(req); resp = client.SmartStructuralOCRV2(req);
} catch (TencentCloudSDKException e) { } catch (TencentCloudSDKException e) {
@@ -106,23 +106,4 @@ public class NavigateService {
JSONObject location = array.getJSONObject(0); JSONObject location = array.getJSONObject(0);
return location.getString("location"); return location.getString("location");
} }
public String deGeoCode(String fomattedLoc) {
Map<String, Object> params = new HashMap<>();
params.put("key", key);
params.put("location", fomattedLoc);
params.put("poitype", "飞机场|火车站|地铁站");
HttpResponse response = HttpRequest.get("https://restapi.amap.com/v3/geocode/regeo")
.form(params)
.execute();
String result = response.body();
response.close();
JSONObject resultObj = JSONObject.parseObject(result);
if (resultObj.getInteger("status")==0) {
return null;
}
JSONObject reGeoCode = resultObj.getJSONObject("regeocode");
String address = reGeoCode.getString("formatted_address");
return address;
}
} }

View File

@@ -1,10 +0,0 @@
package com.ivmiku.tutorial.service;
import org.springframework.stereotype.Service;
@Service
public class RecogintionService {
static {
}
}

View File

@@ -10,7 +10,10 @@ server.port=8432
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root spring.datasource.username=root
spring.datasource.password=Shuodedaoli114514 spring.datasource.password=Shuodedaoli114514
spring.datasource.url=jdbc:mysql://mysql:3306/tutorial?useUnicode=true&characterEncoding=utf8&useSSL=false&ServerTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true 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.server-addr=nacos:8848
spring.cloud.nacos.discovery.enabled=true spring.cloud.nacos.discovery.enabled=true
management.zipkin.tracing.endpoint=http://zipkin:9411/api/v2/spans
management.tracing.sampling.probability=1.0

View File

@@ -10,5 +10,5 @@ dubbo.application.qos-enable=false
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root spring.datasource.username=root
spring.datasource.password=Shuodedaoli114514 spring.datasource.password=12345abcde
spring.datasource.url=jdbc:mysql://154.40.44.199:4514/tutorial?useUnicode=true&characterEncoding=utf8&useSSL=false&ServerTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true spring.datasource.url=jdbc:mysql://127.0.0.1:3306/tutorial?useUnicode=true&characterEncoding=utf8&useSSL=false&ServerTimezone=Asia/Shanghai

View File

@@ -13,7 +13,7 @@
<module>user-8072</module> <module>user-8072</module>
<module>commons</module> <module>commons</module>
<module>community-8073</module> <module>community-8073</module>
<module>navigate-8432</module>
</modules> </modules>
<properties> <properties>
@@ -178,11 +178,6 @@
<artifactId>sa-token-spring-boot3-starter</artifactId> <artifactId>sa-token-spring-boot3-starter</artifactId>
<version>${satoken-version}</version> <version>${satoken-version}</version>
</dependency> </dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-redis-jackson</artifactId>
<version>${satoken-version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.dubbo/dubbo-registry-nacos --> <!-- https://mvnrepository.com/artifact/org.apache.dubbo/dubbo-registry-nacos -->
<dependency> <dependency>
<groupId>org.apache.dubbo</groupId> <groupId>org.apache.dubbo</groupId>

View File

@@ -65,10 +65,45 @@
<groupId>org.apache.commons</groupId> <groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId> <artifactId>commons-pool2</artifactId>
</dependency> </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> <dependency>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId> <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency> </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> <dependency>
<groupId>com.alibaba.cloud</groupId> <groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
@@ -82,14 +117,6 @@
<artifactId>commons</artifactId> <artifactId>commons</artifactId>
<version>1.0-SNAPSHOT</version> <version>1.0-SNAPSHOT</version>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

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

View File

@@ -1,24 +0,0 @@
package com.ivmiku.tutorial.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan("com.ivmiku.tutorial.mapper")
public class MybatisPlusConfig {
/**
* 添加分页插件
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
//interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); 如果有多数据源可以不配具体类型 否则都建议配上具体的DbType
return interceptor;
}
}

View File

@@ -1,42 +0,0 @@
package com.ivmiku.tutorial.config;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitMqConfig {
@Bean
public Queue queue1() {
return new Queue("queue1",true);
}
@Bean
public Queue queue2() {
return new Queue("queue2",true);
}
@Bean
public FanoutExchange exchange1() {
return new FanoutExchange("exchange1",true, false);
}
@Bean
public FanoutExchange exchange2() {
return new FanoutExchange("exchange2",true, false);
}
@Bean
public Binding binding1() {
return BindingBuilder.bind(queue1()).to(exchange1());
}
@Bean
public Binding binding2() {
return BindingBuilder.bind(queue2()).to(exchange2());
}
}

View File

@@ -1,15 +0,0 @@
package com.ivmiku.tutorial.config;
import cn.dev33.satoken.interceptor.SaInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册 Sa-Token 拦截器,打开注解式鉴权功能
registry.addInterceptor(new SaInterceptor()).addPathPatterns("/**");
}
}

View File

@@ -1,34 +0,0 @@
package com.ivmiku.tutorial.config;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
import org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean;
import org.springframework.web.util.WebAppRootListener;
@Configuration
public class WebSocketConfig implements ServletContextInitializer {
@Bean
public ServerEndpointExporter serverEndpointExporter (){
return new ServerEndpointExporter();
}
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
servletContext.addListener(WebAppRootListener.class);
servletContext.setInitParameter("org.apache.tomcat.websocket.textBufferSize","102400000");
}
@Bean
public ServletServerContainerFactoryBean createWebSocketContainer() {
ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
// 在此处设置bufferSize
container.setMaxTextMessageBufferSize(50*1024*1024);
container.setMaxBinaryMessageBufferSize(50*1024*1024);
container.setMaxSessionIdleTimeout(15 * 60000L);
return container;
}
}

View File

@@ -1,39 +0,0 @@
package com.ivmiku.tutorial.controller;
import cn.dev33.satoken.annotation.SaCheckLogin;
import com.alibaba.fastjson2.JSON;
import com.ivmiku.tutorial.entity.HistoryQuery;
import com.ivmiku.tutorial.response.Result;
import com.ivmiku.tutorial.service.MessageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.text.ParseException;
@SaCheckLogin
@RestController
@RequestMapping("/message")
public class MessageController {
@Autowired
private MessageService messageService;
@PostMapping("/history")
public Object getChatHistory(@RequestBody HistoryQuery input) throws ParseException {
Result result = Result.ok();
if (input.getStartDate() != null && input.getEndDate() != null) {
result.setData(messageService.getChatHistoryByDate(input.getUser1Id(), input.getUser2Id(), input.getStartDate(), input.getEndDate(), input.getPage(), input.getSize()));
} else {
if (input.getPage() <= 0 || input.getSize() <=0) {
return Result.error("请输入合法分页参数");
} else {
result.setData(messageService.getChatHistory(input.getUser1Id(), input.getUser2Id(), input.getPage(), input.getSize()));
}
}
return JSON.toJSON(result);
}
@GetMapping("/list")
public Object getChatList(@RequestParam String user_id, @RequestParam int page, @RequestParam int size) {
return Result.ok(messageService.getChatList(user_id, page, size));
}
}

View File

@@ -1,42 +0,0 @@
package com.ivmiku.tutorial.controller;
import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.stp.StpUtil;
import com.ivmiku.tutorial.entity.IgnoreUser;
import com.ivmiku.tutorial.response.Result;
import com.ivmiku.tutorial.service.RelationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@SaCheckLogin
@RestController
@RequestMapping("/relation")
public class RelationController {
@Autowired
private RelationService relationService;
@PostMapping("/ignore")
public Object ignoreUser(@RequestBody IgnoreUser input) {
relationService.IgnoreUser(input.getUserId(), input.getToIgnore());
return Result.ok();
}
@GetMapping("subscribe")
public Object subscribe(@RequestParam String subId) {
String userId = (String) StpUtil.getLoginId();
relationService.subscribe(userId, subId);
return Result.ok();
}
@GetMapping("fan")
public Object getFanList(@RequestParam int page, @RequestParam int size) {
String userId = (String) StpUtil.getLoginId();
return Result.ok(relationService.getFanList(userId, page, size));
}
@GetMapping("follow")
public Object getFollowList(@RequestParam int page, @RequestParam int size) {
String userId = (String) StpUtil.getLoginId();
return Result.ok(relationService.getSubList(userId, page, size));
}
}

View File

@@ -7,10 +7,8 @@ import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSON;
import com.ivmiku.tutorial.entity.User; import com.ivmiku.tutorial.entity.User;
import com.ivmiku.tutorial.entity.UserDTO;
import com.ivmiku.tutorial.mapper.UserMapper; import com.ivmiku.tutorial.mapper.UserMapper;
import com.ivmiku.tutorial.response.Result; import com.ivmiku.tutorial.response.Result;
import com.ivmiku.tutorial.service.UserService;
import com.ivmiku.tutorial.utils.RedisUtil; import com.ivmiku.tutorial.utils.RedisUtil;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.error.WxErrorException;
@@ -30,13 +28,9 @@ public class UserController {
@Resource @Resource
private RedisUtil redisUtil; private RedisUtil redisUtil;
@Resource
private UserService userService;
@GetMapping("/login") @GetMapping("/login")
public Object login(@RequestParam(name = "code") String code, public Object login(@RequestParam(name = "code") String code, @RequestParam(name = "rawdata") String rawData, @RequestParam(name = "signature") String signature
@RequestParam(name = "rawdata") String rawData, ) {
@RequestParam(name = "signature") String signature) {
WxMaJscode2SessionResult session; WxMaJscode2SessionResult session;
try { try {
session = wxMaService.getUserService().getSessionInfo(code); session = wxMaService.getUserService().getSessionInfo(code);
@@ -55,8 +49,6 @@ public class UserController {
user.setOpenid(session.getOpenid()); user.setOpenid(session.getOpenid());
user.setNickname(raw.getString("nickname")); user.setNickname(raw.getString("nickname"));
user.setAvatarUrl(raw.getString("avatarUrl")); user.setAvatarUrl(raw.getString("avatarUrl"));
user.setGender(raw.getString("gender"));
user.setAdmin(false);
userMapper.insert(user); userMapper.insert(user);
} }
map.put("token", StpUtil.getTokenValue()); map.put("token", StpUtil.getTokenValue());
@@ -64,21 +56,4 @@ public class UserController {
WxMaConfigHolder.remove(); WxMaConfigHolder.remove();
return JSON.toJSON(Result.ok(map)); return JSON.toJSON(Result.ok(map));
} }
@GetMapping("/validate")
public Object validate() {
try {
StpUtil.checkLogin();
} catch (Exception e) {
return Result.error(e.getMessage());
}
return Result.ok();
}
@PostMapping("/edit")
public Object editInfo(@RequestBody UserDTO userDTO) {
String loginId = (String) StpUtil.getLoginId();
userService.changeUserInfo(userDTO, loginId);
return Result.ok();
}
} }

View File

@@ -1,166 +0,0 @@
package com.ivmiku.tutorial.controller;
import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ivmiku.tutorial.entity.Message;
import com.ivmiku.tutorial.response.AtNotifier;
import com.ivmiku.tutorial.service.MessageService;
import com.ivmiku.tutorial.service.RelationService;
import com.ivmiku.tutorial.utils.DateUtil;
import com.ivmiku.tutorial.utils.MessageUtil;
import jakarta.websocket.*;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Controller;
import java.io.IOException;
import java.text.ParseException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import static jakarta.websocket.CloseReason.CloseCodes.CLOSED_ABNORMALLY;
@Controller
@ServerEndpoint(value = "/chat/{satoken}")
public class WebSocketServer implements ApplicationContextAware {
public static Map<String, Session> sessionMap = new ConcurrentHashMap<>();
public static Map<String, Integer> controlMap = new HashMap<>();
private static ApplicationContext applicationContext;
@Autowired
private MessageService messageService;
private RabbitTemplate rabbitTemplate;
private RelationService relationService;
@OnMessage
public void onMessage(String message, Session session) throws IOException {
Message msg = JSON.parseObject(message, Message.class);
msg.setDate(DateUtil.getCurrentTime());
if (MessageUtil.checkMessage(msg.getMessage())) {
session.getBasicRemote().sendText("发送的信息含有敏感词,请进行调整");
if (!controlMap.containsKey(msg.getFromId())){
controlMap.put(msg.getFromId(), 0);
}
if (controlMap.get(msg.getFromId()) == 4){
session.getBasicRemote().sendText("由于多次违反社区规则您已被封禁1小时");
session.close(new CloseReason(CLOSED_ABNORMALLY, "账号被封禁"));
StpUtil.kickout(msg.getFromId());
StpUtil.disable(msg.getFromId(), 3600);
controlMap.put(msg.getFromId(), 0);
}
controlMap.put(msg.getFromId(), controlMap.get(msg.getFromId())+1);
} else
if (relationService.ifIgnored(msg.getToId(), msg.getFromId())) {
session.getBasicRemote().sendText("您已被对方屏蔽");
} else {
messageService.insertMessage(msg);
rabbitTemplate.convertAndSend("exchange1", "", JSON.toJSONString(msg));
}
}
@OnOpen
public void onOpen(Session session, EndpointConfig endpointConfig, @PathParam("satoken") String satoken) throws IOException {
String userId = (String) StpUtil.getLoginIdByToken(satoken);
if (userId == null) {
session.getBasicRemote().sendText("Invalid Token");
session.close();
}
this.messageService = WebSocketServer.applicationContext.getBean(MessageService.class);
this.rabbitTemplate = WebSocketServer.applicationContext.getBean(RabbitTemplate.class);
this.relationService = WebSocketServer.applicationContext.getBean(RelationService.class);
sessionMap.put(userId, session);
List<Message> unreadList = messageService.getUnreadMsg(userId);
for(Message msg : unreadList) {
JSONObject object = JSONObject.from(msg);
object.put("type", 1);
session.getBasicRemote().sendText(object.toJSONString());
}
List<AtNotifier> atList = messageService.getAtList(userId);
for (AtNotifier notifier : atList) {
JSONObject object = JSONObject.from(notifier);
object.put("type", 2);
session.getBasicRemote().sendText(object.toJSONString());
}
}
@OnClose
public void onClose(CloseReason closeReason, Session session){
sessionMap.remove(session.getId());
}
@OnError
public void onError(Throwable throwable) throws IOException {
throwable.printStackTrace();
}
public void sendToUser(Message msg) throws IOException, ParseException {
if (sessionMap.containsKey(msg.getToId())){
sessionMap.get(msg.getToId()).getBasicRemote().sendText(JSON.toJSONString(msg));
}
else {
messageService.insertUnreadMsg(msg.getToId(), msg);
}
msg.setChatId(messageService.getChatId(msg.getFromId(), msg.getToId()));
messageService.insertToMysql(msg);
messageService.insertToRedis(msg);
}
public void sendToPublic(Message msg) throws IOException, ParseException {
for (Session session : sessionMap.values()) {
session.getBasicRemote().sendText(JSON.toJSONString(msg));
}
msg.setChatId(messageService.getChatId(msg.getFromId(), msg.getToId()));
messageService.insertToMysql(msg);
messageService.insertToRedis(msg);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
WebSocketServer.applicationContext = applicationContext;
}
@RabbitHandler
@RabbitListener(bindings = @QueueBinding(
value = @Queue(),
exchange = @Exchange(value = "exchange1",type = ExchangeTypes.FANOUT)
))
public void sendMsg(String message) throws IOException {
Message msg = JSON.parseObject(message, Message.class);
if (sessionMap.containsKey(msg.getToId())) {
JSONObject jsonObject = JSONObject.from(msg);
jsonObject.put("type", 1);
sessionMap.get(msg.getToId()).getBasicRemote().sendText(jsonObject.toJSONString());
messageService.deleteMessage(msg);
}
}
@RabbitHandler
@RabbitListener(bindings = @QueueBinding(
value = @Queue(),
exchange = @Exchange(value = "exchange2",type = ExchangeTypes.FANOUT)
))
public void sendAt(String message) throws IOException {
AtNotifier notifier = JSON.parseObject(message, AtNotifier.class);
if (sessionMap.containsKey(notifier.getToId())) {
JSONObject jsonObject = JSONObject.from(notifier);
jsonObject.put("type", 2);
sessionMap.get(notifier.getToId()).getBasicRemote().sendText(jsonObject.toJSONString());
messageService.deleteNotifier(notifier);
}
}
}

View File

@@ -1,18 +0,0 @@
package com.ivmiku.tutorial.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
/**
* @author Aurora
*/
@Data
@TableName("chatid")
public class ChatId {
@TableId(type = IdType.ASSIGN_ID)
private String id;
private String user1Id;
private String user2Id;
}

View File

@@ -1,18 +0,0 @@
package com.ivmiku.tutorial.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author Aurora
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("friend")
public class Friend {
private String user1Id;
private String user2Id;
}

View File

@@ -1,12 +0,0 @@
package com.ivmiku.tutorial.entity;
import lombok.Data;
/**
* @author Aurora
*/
@Data
public class FriendQuery {
private String user1Id;
private String user2Id;
}

View File

@@ -1,16 +0,0 @@
package com.ivmiku.tutorial.entity;
import lombok.Data;
/**
* @author Aurora
*/
@Data
public class HistoryQuery {
private String user1Id;
private String user2Id;
private int page;
private int size;
private String startDate;
private String endDate;
}

View File

@@ -1,21 +0,0 @@
package com.ivmiku.tutorial.entity;
import com.alibaba.fastjson2.annotation.JSONField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author Aurora
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("blacklist")
public class IgnoreUser {
@JSONField(ordinal = 1)
private String userId;
@JSONField(ordinal = 2)
private String toIgnore;
}

View File

@@ -1,25 +0,0 @@
package com.ivmiku.tutorial.entity;
import com.alibaba.fastjson2.annotation.JSONField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
/**
* @author Aurora
*/
@Data
@TableName("message")
public class Message implements Serializable {
@JSONField(ordinal = 1)
private String chatId;
@JSONField(ordinal = 2)
private String fromId;
@JSONField(ordinal = 3)
private String toId;
@JSONField(ordinal = 4)
private String message;
@JSONField(ordinal = 5)
private String date;
}

View File

@@ -1,18 +0,0 @@
package com.ivmiku.tutorial.entity;
import lombok.Data;
@Data
public class SubUser {
private String id;
private String username;
private String avatarUrl;
public static SubUser setUser(User user) {
SubUser subUser = new SubUser();
subUser.setId(user.getOpenid());
subUser.setUsername(user.getNickname());
subUser.setAvatarUrl(user.getAvatarUrl());
return subUser;
}
}

View File

@@ -1,13 +0,0 @@
package com.ivmiku.tutorial.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
/**
* @author Aurora
*/
@TableName("subscribe")
@Data
public class Subscribe {
private Long id;
private Long subId;
}

View File

@@ -11,8 +11,4 @@ public class User {
private String openid; private String openid;
private String nickname; private String nickname;
private String avatarUrl; private String avatarUrl;
private boolean isAdmin;
private String phoneNum;
private String birthday;
private String gender;
} }

View File

@@ -1,12 +0,0 @@
package com.ivmiku.tutorial.entity;
import lombok.Data;
@Data
public class UserDTO {
private String nickname;
private String avatarUrl;
private String phoneNum;
private String birthday;
private String gender;
}

Some files were not shown because too many files have changed in this diff Show More