Compare commits

..

14 Commits

Author SHA1 Message Date
296bf5e4c7 Merge pull request 'main' (#5) from iVMiku/guidance-backend:main into main
Reviewed-on: https://gitea.xinxijishubu.asia/miaozerun/guidance-backend/pulls/5
2024-08-27 17:02:45 +08:00
ivmiku
641449be7c feat: 私信和关注、粉丝功能 2024-08-24 18:19:01 +08:00
ivmiku
7deaba288b feat: 语音识别和预设回答 2024-08-24 18:18:37 +08:00
苏元皓
d6492a9657 新增获赞收藏发布 2024-08-23 15:31:12 +08:00
苏元皓
19f3325b50 mybatis-plus依赖移到子模块 2024-08-13 15:35:08 +08:00
bd8e1f0eed Merge pull request 'pages' (#4) from iVMiku/guidance-backend:main into main
Reviewed-on: https://gitea.xinxijishubu.asia/miaozerun/guidance-backend/pulls/4
2024-08-13 14:22:14 +08:00
苏元皓
9a333175b9 pages 2024-08-13 14:21:38 +08:00
6d902b8eee Merge pull request 'main' (#3) from iVMiku/guidance-backend:main into main
Reviewed-on: https://gitea.xinxijishubu.asia/miaozerun/guidance-backend/pulls/3
2024-08-13 14:03:42 +08:00
苏元皓
ddd0faf296 Merge branch 'main' of https://gitea.xinxijishubu.asia/iVMiku/guidance-backend 2024-08-13 14:02:24 +08:00
苏元皓
b755ecfeef 分页 将mybatis-plus依赖移到子模块 2024-08-13 14:02:11 +08:00
312bccf7aa Merge pull request 'main' (#2) from iVMiku/guidance-backend:main into main
Reviewed-on: https://gitea.xinxijishubu.asia/miaozerun/guidance-backend/pulls/2
2024-08-13 14:01:26 +08:00
ivmiku
14e9974c77 feat: 语音助手相关api 2024-08-12 20:18:10 +08:00
苏元皓
e2a408488f 更新标签 2024-08-12 17:37:38 +08:00
苏元皓
1bc3861828 修改pom 2024-08-09 10:08:36 +08:00
76 changed files with 2818 additions and 207 deletions

2
.idea/encodings.xml generated
View File

@@ -7,6 +7,8 @@
<file url="file://$PROJECT_DIR$/community-8073/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/gateway-8133/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/gateway-8133/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/navigate-8432/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/navigate-8432/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/user-8072/src/main/java" charset="UTF-8" />

3
.idea/misc.xml generated
View File

@@ -5,10 +5,11 @@
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
<option value="$PROJECT_DIR$/navigate-8432/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" project-jdk-name="21" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="21" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

View File

@@ -39,6 +39,26 @@
<option name="modulePath" value="$PROJECT_DIR$/community-8073" />
<option name="packageName" value="mapper" />
</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>
</option>
<option name="needsModel" value="true" />
@@ -47,8 +67,8 @@
<option name="tableUIInfoList">
<list>
<TableUIInfo>
<option name="className" value="Usercommunity" />
<option name="tableName" value="usercommunity" />
<option name="className" value="BrowingHistory" />
<option name="tableName" value="browing_history" />
</TableUIInfo>
</list>
</option>

View File

@@ -24,6 +24,28 @@
<!-- <artifactId>springfox-boot-starter</artifactId>-->
<!-- <version>3.0.0</version>-->
<!-- </dependency>-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.7</version>
</dependency>
<!-- 集成redis依赖 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>1.28.0</version>
</dependency>
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
@@ -58,10 +80,30 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.mybatis</groupId>-->
<!-- <artifactId>mybatis</artifactId>-->
<!-- <version>3.5.6</version>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>com.baomidou</groupId>-->
<!-- <artifactId>mybatis-plus-spring-boot3-starter</artifactId>-->
<!-- <exclusions>-->
<!-- <exclusion>-->
<!-- <groupId>org.mybatis</groupId>-->
<!-- <artifactId>mybatis</artifactId>-->
<!-- </exclusion>-->
<!-- </exclusions>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.mybatis</groupId>-->
<!-- <artifactId>mybatis</artifactId>-->
<!-- <version>3.5.6</version>-->
<!-- </dependency>-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
@@ -76,11 +118,11 @@
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<!-- Sa-Token 权限认证在线文档https://sa-token.cc -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot3-starter</artifactId>
</dependency>
<!-- &lt;!&ndash; Sa-Token 权限认证在线文档https://sa-token.cc &ndash;&gt;-->
<!-- <dependency>-->
<!-- <groupId>cn.dev33</groupId>-->
<!-- <artifactId>sa-token-spring-boot3-starter</artifactId>-->
<!-- </dependency>-->
<!-- fastjson2 -->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
@@ -157,7 +199,7 @@
<artifactId>spring-boot-maven-plugin</artifactId>
<version>3.0.13</version>
<configuration>
<mainClass>com.ivmiku.tutorial.Main8072</mainClass>
<mainClass>com.ivmiku.tutorial.Main8073</mainClass>
<layout>JAR</layout>
</configuration>
<executions>

View File

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

@@ -0,0 +1,61 @@
package com.ivmiku.tutorial.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
// 定义一个Bean名称为"redisTemplate"返回类型为RedisTemplate<String, Object>
@Bean(name = "redisTemplate")
public RedisTemplate<String, Object> getRedisTemplate(RedisConnectionFactory factory) {
// 创建一个新的RedisTemplate实例用于操作Redis
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
// 设置RedisTemplate使用的连接工厂以便它能够连接到Redis服务器
redisTemplate.setConnectionFactory(factory);
// 创建一个StringRedisSerializer实例用于序列化Redis的key为字符串
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// 创建一个ObjectMapper实例用于处理JSON的序列化和反序列化
ObjectMapper objectMapper = new ObjectMapper();
// 设置ObjectMapper的属性访问级别以便能够序列化对象的所有属性
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 启用默认的类型信息,以便在反序列化时能够知道对象的实际类型
// 注意这里使用了新的方法替换了过期的enableDefaultTyping方法
// 方法过期,改为下面代码
// objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,
ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(objectMapper, Object.class);
// 设置RedisTemplate的key序列化器为stringRedisSerializer
redisTemplate.setKeySerializer(stringRedisSerializer); // key的序列化类型
// 设置RedisTemplate的value序列化器为jackson2JsonRedisSerializer
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); // value的序列化类型
// 设置RedisTemplate的hash key序列化器为stringRedisSerializer
redisTemplate.setHashKeySerializer(stringRedisSerializer); // key的序列化类型
// 设置RedisTemplate的hash value序列化器为jackson2JsonRedisSerializer
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer); // value的序列化类型
// 调用RedisTemplate的afterPropertiesSet方法该方法会执行一些初始化操作比如检查序列化器是否设置等
redisTemplate.afterPropertiesSet();
// 返回配置好的RedisTemplate实例
return redisTemplate;
}
}

View File

@@ -0,0 +1,17 @@
package com.ivmiku.tutorial.config;
import cn.dev33.satoken.interceptor.SaAnnotationInterceptor;
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 SaTokenConfig implements WebMvcConfigurer {
// 注册Sa-Token的注解拦截器打开注解式鉴权功能
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册注解拦截器,并排除不需要注解鉴权的接口地址 (与登录拦截器无关)
registry.addInterceptor(new SaAnnotationInterceptor())
.addPathPatterns("/**");
}
}

View File

@@ -1,7 +1,11 @@
package com.ivmiku.tutorial.controller;
import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.pagehelper.PageInfo;
import com.ivmiku.tutorial.entity.Comment;
import com.ivmiku.tutorial.entity.Pages;
import com.ivmiku.tutorial.response.Result;
import com.ivmiku.tutorial.service.CommentService;
import com.ivmiku.tutorial.service.FileService;
@@ -19,6 +23,7 @@ import java.util.List;
*/
@RestController
@RequestMapping("/comments")
@SaCheckLogin
public class CommentController {
private static final Logger logger = LoggerFactory.getLogger(CommentController.class);
@@ -200,11 +205,12 @@ public class CommentController {
* @param postId 帖子的唯一标识ID
* @return 返回操作结果和评论列表
*/
@GetMapping("/post/{postId}")
@PostMapping("/post/{postId}")
@Operation(summary = "获取帖子下的所有评论")
public Result getPostComments(@PathVariable("postId") Long postId) {
public Result getPostComments(@PathVariable("postId") Long postId, @RequestBody Pages pages) {
logger.info("获取帖子ID{}的评论列表", postId);
List<Comment> comments = commentService.getPostComments(postId);
logger.info("获取pageSize{}", pages.getPageSize());
IPage<Comment> comments = commentService.getPostComments(postId, pages.getPageNum(), pages.getPageSize());
return Result.ok(comments);
}
@@ -216,9 +222,9 @@ public class CommentController {
*/
@GetMapping("/replies/{commentId}")
@Operation(summary = "获取评论下的所有回复")
public Result getCommentReplies(@PathVariable Long commentId) {
public Result getCommentReplies(@PathVariable Long commentId, @RequestBody Pages pages) {
logger.info("获取评论ID{}的回复列表", commentId);
List<Comment> replies = commentService.getCommentReplies(commentId);
IPage<Comment> replies = commentService.getCommentReplies(commentId, pages.getPageNum(), pages.getPageSize());
return Result.ok(replies);
}

View File

@@ -1,8 +1,10 @@
package com.ivmiku.tutorial.controller;
import cn.dev33.satoken.annotation.SaCheckLogin;
import com.ivmiku.tutorial.entity.Community;
import com.ivmiku.tutorial.response.Result;
import com.ivmiku.tutorial.service.CommunityService;
import com.ivmiku.tutorial.service.CommunitytagService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.models.annotations.OpenAPI30;
import org.apiguardian.api.API;
@@ -18,7 +20,7 @@ import java.util.List;
*/
@RestController
@RequestMapping("/communities")
@SaCheckLogin
public class CommunityController {
// 使用SLF4J的LoggerFactory来创建一个日志记录器

View File

@@ -0,0 +1,47 @@
package com.ivmiku.tutorial.controller;
import com.ivmiku.tutorial.entity.Communitytag;
import com.ivmiku.tutorial.response.Result;
import com.ivmiku.tutorial.service.CommunitytagService;
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")
public Result createCommunityTag(@RequestBody Communitytag communityTag) {
communitytagService.createCommunityTag(communityTag);
return Result.ok();
}
@PutMapping("/update/{id}")
public Result updateCommunityTag(@PathVariable Long id, @RequestBody Communitytag communityTag) {
communitytagService.updateCommunityTag(id, communityTag);
return Result.ok();
}
@DeleteMapping("/delete/{id}")
public Result deleteCommunityTag(@PathVariable Long id) {
communitytagService.deleteCommunityTag(id);
return Result.ok();
}
@GetMapping("/get/{id}")
public Result getCommunityTag(@PathVariable Long id) {
Communitytag communityTag = communitytagService.getCommunityTagById(id);
return Result.ok(communityTag);
}
@GetMapping("/list/{communityId}")
public Result getCommunityTagListByCommunityId(@PathVariable Long communityId) {
List<Communitytag> tags = communitytagService.getCommunityTagListByCommunityId(communityId);
return Result.ok(tags);
}
}

View File

@@ -1,12 +1,18 @@
package com.ivmiku.tutorial.controller;
import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.lang.hash.Hash;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.ivmiku.tutorial.entity.Post;
import com.ivmiku.tutorial.response.Result;
import com.ivmiku.tutorial.service.InteractionService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
/**
* InteractionController 是处理用户与帖子的收藏、点赞以及对评论的点赞功能的控制器类。
@@ -14,6 +20,7 @@ import javax.annotation.Resource;
@Slf4j
@RestController
@RequestMapping("/interaction")
@SaCheckLogin
public class InteractionController {
@Resource
@@ -102,4 +109,35 @@ public class InteractionController {
interactionService.unlikeComment(userOpenid, commentId);
return Result.ok();
}
/**
* 我的收藏接口
* @return
*/
@GetMapping("/getFavoritePosts")
public Result getFavoritePosts() {
String userOpenid = StpUtil.getLoginIdAsString();
log.info("用户 {} 正在获取收藏的帖子", userOpenid);
IPage<Post> favoritePost = interactionService.getFavoritePosts(userOpenid);
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")
public Result getLikeCount() {
String userOpenid = StpUtil.getLoginIdAsString();
log.info("用户 {} 正在获取用户获赞的数量", userOpenid);
HashMap<String, Object> res = interactionService.getLikeCount(userOpenid);
return Result.ok();
}
}

View File

@@ -1,6 +1,10 @@
package com.ivmiku.tutorial.controller;
import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.pagehelper.PageInfo;
import com.ivmiku.tutorial.entity.Pages;
import com.ivmiku.tutorial.entity.Post;
import com.ivmiku.tutorial.response.Result;
import com.ivmiku.tutorial.service.FileService;
@@ -12,13 +16,16 @@ import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 帖子控制器用于处理帖子相关的HTTP请求。
*/
@RestController
@RequestMapping("/post")
@SaCheckLogin
public class PostController {
private static final Logger logger = LoggerFactory.getLogger(PostController.class);
@@ -34,7 +41,9 @@ public class PostController {
@RequestParam("content") String content,
@RequestParam("communityId") Long communityId,
@RequestParam("imageFiles") MultipartFile[] imageFiles,
@RequestParam("videoFile") MultipartFile videoFile) {
@RequestParam("videoFile") MultipartFile videoFile,
@RequestParam("isPublic") Integer isPublic,
@RequestParam("location") String location) {
String userId = StpUtil.getLoginIdAsString();
logger.info("用户ID{}开始创建帖子", userId);
@@ -43,6 +52,8 @@ public class PostController {
post.setTitle(title);
post.setContent(content);
post.setCommunityId(communityId);
post.setIsPublic(isPublic);
post.setLocation(location);
try {
// 上传视频
if (videoFile != null && !videoFile.isEmpty()) {
@@ -73,7 +84,8 @@ public class PostController {
@GetMapping("/get/{id}")
public Result getPost(@PathVariable Long id) {
logger.info("开始获取帖子ID{}的详细信息", id);
Post post = postService.getPostById(id); // 调用服务层根据ID查询帖子
String userId = StpUtil.getLoginIdAsString();
Post post = postService.getPostById(id, userId); // 调用服务层根据ID查询帖子
if (post != null) {
logger.info("帖子ID{}的详细信息获取成功", id);
} else {
@@ -102,24 +114,27 @@ public class PostController {
/**
* 用户获取自己所有帖子的信息
* @return 当前用户帖子列表
* @return 当前用户帖子列表与该用户的总发布数量
*/
@GetMapping("/getPostList")
public Result getPostList() {
public Result getPostList(@RequestBody Pages pages) {
logger.info("开始获取帖子列表");
String userId = StpUtil.getLoginIdAsString(); // 获取当前登录用户的ID
List<Post> posts = postService.getPostList(userId);
return Result.ok(posts); // 调用服务层获取帖子列表
IPage<Post> posts = postService.getPostList(userId, pages.getPageNum(), pages.getPageSize());
Map<String, Object> data = new HashMap<>();
data.put("total", posts.getTotal());
data.put("posts", posts);
return Result.ok(data); // 调用服务层获取帖子列表
}
/**
* 社区获取自己所有帖子的信息
* @return 当前用户帖子列表
*/
@GetMapping("/getCommunityPostList{communityId}")
public Result getCommunityPostList(@PathVariable("communityId") Long communityId) {
@GetMapping("/getCommunityPostList/{communityId}")
public Result getCommunityPostList(@PathVariable("communityId") Long communityId, @RequestBody Pages pages) {
logger.info("开始获取帖子列表");
List<Post> posts = postService.getCommunityPostList(communityId);
IPage<Post> posts = postService.getCommunityPostList(communityId, pages.getPageNum(), pages.getPageSize());
return Result.ok(posts); // 调用服务层获取帖子列表
}
@@ -128,8 +143,8 @@ public class PostController {
* @return
*/
@GetMapping("/official")
public List<Post> getOfficialPosts() {
return postService.getOfficialPosts();
public IPage<Post> getOfficialPosts(@RequestBody Pages pages) {
return postService.getOfficialPosts(pages.getPageNum(), pages.getPageSize());
}
/**
@@ -137,7 +152,16 @@ public class PostController {
* @return
*/
@GetMapping("/nonOfficial")
public List<Post> getNonOfficialPosts() {
return postService.getNonOfficialPosts();
public IPage<Post> getNonOfficialPosts(@RequestBody Pages pages) {
return postService.getNonOfficialPosts(pages.getPageNum(), pages.getPageSize());
}
@PutMapping("/changePublic")
public Result changePublic(@RequestParam Long postId, @RequestParam Integer isPublic) {
String userId = StpUtil.getLoginIdAsString(); // 获取当前登录用户的ID
logger.info("用户ID{}开始修改帖子ID{}的公开状态", userId, postId);
postService.changePublic(postId, isPublic); // 调用服务层修改帖子公开状态
logger.info("用户ID{}的帖子ID{}修改成功", userId, postId);
return Result.ok();
}
}

View File

@@ -1,5 +1,6 @@
package com.ivmiku.tutorial.controller;
import cn.dev33.satoken.annotation.SaCheckLogin;
import com.ivmiku.tutorial.entity.Post;
import com.ivmiku.tutorial.entity.PostTag;
import com.ivmiku.tutorial.entity.Tag;
@@ -14,22 +15,14 @@ import java.util.List;
@RestController
@RequestMapping("/post-tag")
@SaCheckLogin
public class PostTagController {
// 日志记录器,用于记录控制器中的日志信息
private static final Logger logger = LoggerFactory.getLogger(PostTagController.class);
// 通过@Autowired注解自动装配PostTagService服务
@Autowired
private PostTagService postTagService;
/**
* 创建帖子标签接口。
* 用户通过POST请求提交帖子标签数据服务端接收并保存帖子标签。
*
* @param postTag 提交的帖子标签数据
* @return Result 返回操作结果
*/
@PostMapping("/create")
public Result createPostTag(@RequestBody PostTag postTag) {
logger.info("开始创建帖子标签");
@@ -38,13 +31,6 @@ public class PostTagController {
return Result.ok();
}
/**
* 获取帖子标签详情接口。
* 根据帖子标签ID获取帖子标签的详细信息。
*
* @param id 帖子标签的唯一标识ID
* @return Result 返回操作结果和帖子标签详情
*/
@GetMapping("/get/{id}")
public Result getPostTag(@PathVariable Long id) {
logger.info("开始获取帖子标签ID{}的详细信息", id);
@@ -57,14 +43,6 @@ public class PostTagController {
return Result.ok(postTag);
}
/**
* 更新帖子标签接口。
* 用户通过PUT请求提交更新后的帖子标签数据服务端接收并更新帖子标签。
*
* @param id 要更新的帖子标签的唯一标识ID
* @param postTag 更新后的帖子标签数据
* @return Result 返回操作结果
*/
@PutMapping("/update/{id}")
public Result updatePostTag(@PathVariable Long id, @RequestBody PostTag postTag) {
logger.info("开始更新帖子标签ID{}", id);
@@ -73,13 +51,6 @@ public class PostTagController {
return Result.ok();
}
/**
* 删除帖子标签接口。
* 根据帖子标签ID删除指定的帖子标签。
*
* @param id 要删除的帖子标签的唯一标识ID
* @return Result 返回操作结果
*/
@DeleteMapping("/delete/{id}")
public Result deletePostTag(@PathVariable Long id) {
logger.info("开始删除帖子标签ID{}", id);
@@ -88,25 +59,24 @@ public class PostTagController {
return Result.ok();
}
/**
* 获取当前帖子所有标签列表接口。
* @return
*/
@GetMapping("/getPostTagList{postId}")
public Result getPostTagList(@PathVariable("postId") Long postId) {
@GetMapping("/getPostTagList/{postId}")
public Result getPostTagList(@PathVariable Long postId) {
logger.info("开始获取帖子标签列表");
List<Tag> tags = postTagService.getPostTagList(postId);
return Result.ok(tags);
}
/**
* 获取当前标签所有帖子列表接口。
* @return
*/
@GetMapping("/getTagPostList{tagId}")
public Result getTagPostList(@PathVariable("tagId") Long tagId) {
logger.info("开始获取帖子标签列表");
@GetMapping("/getTagPostList/{tagId}")
public Result getTagPostList(@PathVariable Long tagId) {
logger.info("开始获取标签帖子列表");
List<Post> posts = postTagService.getTagPostList(tagId);
return Result.ok(posts);
}
@GetMapping("/topTags")
public Result getTopTags(@RequestParam(defaultValue = "10") int topN) {
logger.info("开始获取前{}个使用次数最多的标签", topN);
List<String> tags = postTagService.getTopTags(topN);
return Result.ok(tags);
}
}

View File

@@ -1,5 +1,6 @@
package com.ivmiku.tutorial.controller;
import cn.dev33.satoken.annotation.SaCheckLogin;
import com.ivmiku.tutorial.entity.Tag;
import com.ivmiku.tutorial.response.Result;
import com.ivmiku.tutorial.service.PostTagService;
@@ -13,12 +14,12 @@ import java.util.List;
@RestController
@RequestMapping("/tag")
@SaCheckLogin
public class TagController {
// 日志记录器,用于记录控制器中的日志信息
private static final Logger logger = LoggerFactory.getLogger(TagController.class);
// 通过@Autowired注解自动装配TagService服务
@Autowired
private TagService tagService;

View File

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

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

@@ -0,0 +1,12 @@
package com.ivmiku.tutorial.entity;
import lombok.Data;
@Data
public class Pages {
private Integer pageNum;
private Integer pageSize;
}

View File

@@ -25,13 +25,17 @@ public class Post implements Serializable {
private String content;
private String videoUrl; // 新增字段,存储视频URL
private String videoUrl; // 存储视频URL
private String imageUrls; // 新增字段,存储图片URL多个URL用分号分隔
private String imageUrls; // 存储图片URL多个URL用分号分隔
private Integer isDeleted;
private Integer isOfficial; // 新增字段,标记是否为官方创建的帖子
private Integer isOfficial; // 标记是否为官方创建的帖子
private Integer isPublic; // 标记帖子是否公开 0非公开 1公开
private String location; // 存储帖子位置信息
private Date createdAt;

View File

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

@@ -0,0 +1,18 @@
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,6 +2,8 @@ package com.ivmiku.tutorial.mapper;
import com.ivmiku.tutorial.entity.Likee;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
/**
* @author rog
@@ -11,6 +13,14 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
*/
public interface LikeMapper extends BaseMapper<Likee> {
// 获取帖子获赞数
@Select("SELECT SUM(like_count) FROM posts WHERE user_openid = #{userOpenid}")
Long getPostLikeCount(@Param("userOpenid") String userOpenid);
// 获取评论获赞数
@Select("SELECT SUM(like_count) FROM comments WHERE user_openid = #{userOpenid}")
Long getCommentLikeCount(@Param("userOpenid") String userOpenid);
}

View File

@@ -0,0 +1,18 @@
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,5 +1,7 @@
package com.ivmiku.tutorial.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.pagehelper.PageInfo;
import com.ivmiku.tutorial.entity.Comment;
import com.baomidou.mybatisplus.extension.service.IService;
@@ -49,10 +51,9 @@ public interface CommentService extends IService<Comment> {
void deleteComment(Long commentId, String userId);
List<Comment> getPostComments(Long postId);
List<Comment> getCommentReplies(Long commentId);
IPage<Comment> getPostComments(Long postId, int pageNum, int pageSize);
IPage<Comment> getCommentReplies(Long commentId, int pageNum, int pageSize);
/**
* 回复评论。

View File

@@ -0,0 +1,24 @@
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,5 +1,11 @@
package com.ivmiku.tutorial.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.ivmiku.tutorial.entity.Post;
import java.util.HashMap;
import java.util.List;
/**
* InteractionService接口定义用户对帖子和评论的收藏与点赞操作。
*/
@@ -10,4 +16,8 @@ public interface InteractionService {
void unlikePost(String userOpenid, Long postId);
void likeComment(String userOpenid, Long commentId);
void unlikeComment(String userOpenid, Long commentId);
IPage<Post> getFavoritePosts(String userOpenid);
HashMap<String, Object> getLikeCount(String userOpenid);
}

View File

@@ -1,5 +1,7 @@
package com.ivmiku.tutorial.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.github.pagehelper.PageInfo;
import com.ivmiku.tutorial.entity.Post;
import com.baomidou.mybatisplus.extension.service.IService;
@@ -7,15 +9,18 @@ import java.util.List;
public interface PostService extends IService<Post> {
void createPost(Post post);
Post getPostById(Long postId);
Post getPostById(Long postId, String userOpenid);
void updatePost(Long postId, String userId, Post post);
void deletePost(Long postId, String userId);
List<Post> getPostList(String userId);
IPage<Post> getPostList(String userId, int pageNum, int pageSize);
List<Post> getCommunityPostList(Long communityId);
IPage<Post> getCommunityPostList(Long communityId, int pageNum, int pageSize);
List<Post> getOfficialPosts(); // 新增获取官方帖子的方法
IPage<Post> getOfficialPosts(int pageNum, int pageSize);
List<Post> getNonOfficialPosts(); // 新增获取非官方帖子的方法
IPage<Post> getNonOfficialPosts(int pageNum, int pageSize);
void changePublic(Long postId, Integer isPublic);
}

View File

@@ -51,4 +51,6 @@ public interface PostTagService extends IService<PostTag> {
List<Post> getTagPostList(Long tagId);
List<Tag> getSortedTagList();
List<String> getTopTags(int topN);
}

View File

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

@@ -2,6 +2,10 @@ package com.ivmiku.tutorial.service.impl;
import cn.dev33.satoken.stp.StpUtil;
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.PageInfo;
import com.ivmiku.tutorial.entity.Comment;
import com.ivmiku.tutorial.mapper.CommentMapper;
import com.ivmiku.tutorial.service.CommentService;
@@ -11,7 +15,6 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.sql.Timestamp;
import java.util.List;
@@ -102,19 +105,29 @@ public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> impl
* @return List<Comment> 返回评论列表
*/
@Override
public List<Comment> getPostComments(Long postId) {
logger.info("开始获取帖子ID{}的评论列表", postId);
public IPage<Comment> getPostComments(Long postId, int pageNum, int pageSize) {
logger.info("开始获取帖子ID{}的评论列表,第{}页,每页{}条", postId, pageNum, pageSize);
// 设置分页参数
// PageHelper.startPage(pageNum, pageSize);
IPage<Comment> page = new Page<>(pageNum, pageSize);
// 查询评论
LambdaQueryWrapper<Comment> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Comment::getPostId, postId).eq(Comment::getIsDeleted, 0);
List<Comment> comments = commentMapper.selectList(wrapper);
IPage<Comment> comments = commentMapper.selectPage(page, wrapper);
if (comments != null) {
logger.info("获取帖子ID{}的评论列表成功", postId);
} else {
logger.warn("帖子ID{}的评论列表为空", postId);
}
// 使用 PageInfo 包装结果
return comments;
}
/**
* 获取评论下的所有回复。
*
@@ -122,16 +135,24 @@ public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> impl
* @return List<Comment> 返回回复列表
*/
@Override
public List<Comment> getCommentReplies(Long commentId) {
logger.info("开始获取评论ID{}的回复列表", commentId);
public IPage<Comment> getCommentReplies(Long commentId, int pageNum, int pageSize) {
logger.info("开始获取评论ID{}的回复列表,第{}页,每页{}条", commentId, pageNum, pageSize);
// 设置分页参数
// PageHelper.startPage(pageNum, pageSize);
IPage<Comment> page = new Page<>(pageNum, pageSize);
// 查询回复
LambdaQueryWrapper<Comment> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Comment::getParentCommentId, commentId).eq(Comment::getIsDeleted, 0);
List<Comment> replies = commentMapper.selectList(wrapper);
IPage<Comment> replies = commentMapper.selectPage(page, wrapper);
if (replies != null) {
logger.info("获取评论ID{}的回复列表成功", commentId);
} else {
logger.warn("评论ID{}的回复列表为空", commentId);
}
// 使用 PageInfo 包装结果
return replies;
}
/**

View File

@@ -0,0 +1,50 @@
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,15 +1,22 @@
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.ivmiku.tutorial.entity.Favorite;
import com.ivmiku.tutorial.entity.Likee;
import com.ivmiku.tutorial.entity.Post;
import com.ivmiku.tutorial.mapper.FavoriteMapper;
import com.ivmiku.tutorial.mapper.LikeMapper;
import com.ivmiku.tutorial.service.InteractionService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ivmiku.tutorial.service.PostService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
/**
* InteractionServiceImpl 实现了 InteractionService 接口,处理用户对帖子和评论的收藏与点赞操作。
@@ -24,6 +31,9 @@ public class InteractionServiceImpl implements InteractionService {
@Resource
private LikeMapper likeMapper;
@Resource
private PostService postService;
@Override
public void favoritePost(String userOpenid, Long postId) {
log.info("User {} is favoriting post {}", userOpenid, postId);
@@ -95,4 +105,60 @@ public class InteractionServiceImpl implements InteractionService {
likeMapper.updateById(likee);
}
}
@Override
public IPage<Post> getFavoritePosts(String userOpenid) {
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, 1, 10);
}
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
}
Long myTotalPost = getFavoritePosts(userOpenid).getTotal();
res.put("myTotalPost", myTotalPost);
return res;
}
}

View File

@@ -1,18 +1,20 @@
package com.ivmiku.tutorial.service.impl;
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.BrowingHistory;
import com.ivmiku.tutorial.entity.Post;
import com.ivmiku.tutorial.mapper.PostMapper;
import com.ivmiku.tutorial.service.BrowingHistoryService;
import com.ivmiku.tutorial.service.PostService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.sql.Timestamp;
import java.util.List;
import java.util.Date;
@Service
public class PostServiceImpl extends ServiceImpl<PostMapper, Post> implements PostService {
@@ -22,6 +24,9 @@ public class PostServiceImpl extends ServiceImpl<PostMapper, Post> implements Po
@Autowired
private PostMapper postMapper;
@Autowired
private BrowingHistoryService browingHistoryService;
@Override
public void createPost(Post post) {
logger.info("开始创建帖子");
@@ -33,9 +38,25 @@ public class PostServiceImpl extends ServiceImpl<PostMapper, Post> implements Po
}
@Override
public Post getPostById(Long postId) {
logger.info("开始根据ID获取帖子详情帖子ID{}", postId);
return getById(postId);
public Post getPostById(Long postId, String userOpenid) {
logger.info("用户openid{} 开始根据ID获取帖子详情帖子ID{}", userOpenid, postId);
// 查找帖子信息
Post post = postMapper.selectById(postId);
if (post == null || post.getIsDeleted() == 1) {
logger.warn("帖子ID{}不存在或已删除", postId);
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;
}
@Override
@@ -62,38 +83,91 @@ public class PostServiceImpl extends ServiceImpl<PostMapper, Post> implements Po
}
@Override
public List<Post> getPostList(String userId) {
logger.info("用户ID{}开始获取帖子列表", userId);
public IPage<Post> getPostList(String userId, int pageNum, int pageSize) {
logger.info("用户ID{}开始获取帖子列表,第{}页,每页{}条", userId, pageNum, pageSize);
// 设置分页参数
// PageHelper.startPage(pageNum, pageSize);
IPage<Post> page = new Page<>(pageNum, pageSize);
LambdaQueryWrapper<Post> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Post::getUserOpenid, userId);
List<Post> posts = postMapper.selectList(wrapper);
wrapper.eq(Post::getIsDeleted, 0);
wrapper.eq(Post::getIsPublic, 1);
IPage<Post> posts = postMapper.selectPage(page, wrapper);
// 使用PageInfo封装分页结果
// PageInfo<Post> pageInfo = new PageInfo<>(posts);
return posts;
}
@Override
public List<Post> getCommunityPostList(Long communityId) {
logger.info("开始获取社区ID{}的帖子列表", communityId);
public IPage<Post> getCommunityPostList(Long communityId, int pageNum, int pageSize) {
logger.info("开始获取社区ID{}的帖子列表,第{}页,每页{}条", communityId, pageNum, pageSize);
// 设置分页参数
// PageHelper.startPage(pageNum, pageSize);
IPage<Post> page = new Page<>(pageNum, pageSize);
LambdaQueryWrapper<Post> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Post::getCommunityId, communityId);
List<Post> posts = postMapper.selectList(wrapper);
wrapper.eq(Post::getIsDeleted, 0);
wrapper.eq(Post::getIsPublic, 1);
IPage<Post> posts = postMapper.selectPage(page, wrapper);
// 使用PageInfo封装分页结果
// PageInfo<Post> pageInfo = new PageInfo<>(posts);
return posts;
}
@Override
public List<Post> getOfficialPosts() {
logger.info("开始获取所有官方创建的帖子");
public IPage<Post> getOfficialPosts(int pageNum, int pageSize) {
logger.info("开始获取所有官方创建的帖子,第{}页,每页{}条", pageNum, pageSize);
// 设置分页参数
// PageHelper.startPage(pageNum, pageSize);
IPage<Post> page = new Page<>(pageNum, pageSize);
LambdaQueryWrapper<Post> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Post::getIsOfficial, 1);
List<Post> posts = postMapper.selectList(wrapper);
wrapper.eq(Post::getIsDeleted, 0);
wrapper.eq(Post::getIsPublic, 1);
IPage<Post> posts = postMapper.selectPage(page, wrapper);
// 使用PageInfo封装分页结果
// PageInfo<Post> pageInfo = new PageInfo<>(posts);
return posts;
}
@Override
public List<Post> getNonOfficialPosts() {
logger.info("开始获取所有非官方创建的帖子");
public IPage<Post> getNonOfficialPosts(int pageNum, int pageSize) {
logger.info("开始获取所有非官方创建的帖子,第{}页,每页{}条", pageNum, pageSize);
// 设置分页参数
// PageHelper.startPage(pageNum, pageSize);
IPage<Post> page = new Page<>(pageNum, pageSize);
LambdaQueryWrapper<Post> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Post::getIsOfficial, 0);
List<Post> posts = postMapper.selectList(wrapper);
wrapper.eq(Post::getIsDeleted, 0);
wrapper.eq(Post::getIsPublic, 1);
IPage<Post> posts = postMapper.selectPage(page, wrapper);
// 使用PageInfo封装分页结果
// PageInfo<Post> pageInfo = new PageInfo<>(posts);
return posts;
}
@Override
public void changePublic(Long postId, Integer isPublic) {
LambdaQueryWrapper<Post> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Post::getPostId, postId);
Post post = postMapper.selectById(postId);
post.setIsPublic(isPublic);
postMapper.update(post, wrapper);
}
}

View File

@@ -11,9 +11,12 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* 帖子标签服务实现类。
@@ -21,7 +24,6 @@ import java.util.List;
@Service
public class PostTagServiceImpl extends ServiceImpl<PostTagMapper, PostTag> implements PostTagService {
// 日志记录器,用于记录服务层的日志信息
private static final Logger logger = LoggerFactory.getLogger(PostTagServiceImpl.class);
@Autowired
@@ -33,39 +35,26 @@ public class PostTagServiceImpl extends ServiceImpl<PostTagMapper, PostTag> impl
@Autowired
private PostTagMapper postTagMapper;
/**
* 创建帖子标签。
* 将帖子标签数据保存到数据库。
*
* @param postTag 要保存的帖子标签数据
*/
@Autowired
private StringRedisTemplate redisTemplate;
private static final String TAG_KEY = "tags";
@Override
public void createPostTag(PostTag postTag) {
logger.info("开始创建帖子标签");
save(postTag);
// 更新标签的使用次数
redisTemplate.opsForZSet().incrementScore(TAG_KEY, postTag.getTagId().toString(), 1);
logger.info("帖子标签创建成功标签ID{}", postTag.getPostTagId());
}
/**
* 根据ID获取帖子标签详情。
* 从数据库中根据帖子标签ID获取帖子标签的详细信息。
*
* @param postTagId 帖子标签的唯一标识ID
* @return PostTag 返回查询到的帖子标签对象
*/
@Override
public PostTag getPostTagById(Long postTagId) {
logger.info("开始根据ID获取帖子标签详情标签ID{}", postTagId);
return getById(postTagId);
}
/**
* 更新帖子标签。
* 根据帖子标签ID更新帖子标签的内容。
*
* @param postTagId 要更新的帖子标签的唯一标识ID
* @param postTag 更新后的帖子标签数据
*/
@Override
public void updatePostTag(Long postTagId, PostTag postTag) {
logger.info("开始更新帖子标签标签ID{}", postTagId);
@@ -74,15 +63,14 @@ public class PostTagServiceImpl extends ServiceImpl<PostTagMapper, PostTag> impl
logger.info("帖子标签更新成功标签ID{}", postTagId);
}
/**
* 删除帖子标签。
* 根据帖子标签ID删除指定的帖子标签。
*
* @param postTagId 要删除的帖子标签的唯一标识ID
*/
@Override
public void deletePostTag(Long postTagId) {
logger.info("开始删除帖子标签标签ID{}", postTagId);
// 删除标签时减少使用次数
PostTag postTag = getById(postTagId);
if (postTag != null) {
redisTemplate.opsForZSet().incrementScore(TAG_KEY, postTag.getTagId().toString(), -1);
}
removeById(postTagId);
logger.info("帖子标签删除成功标签ID{}", postTagId);
}
@@ -104,4 +92,14 @@ public class PostTagServiceImpl extends ServiceImpl<PostTagMapper, PostTag> impl
logger.info("开始获取排序后的标签列表");
return tagMapper.getSortedTagList();
}
@Override
public List<String> getTopTags(int topN) {
logger.info("开始获取前{}个使用次数最多的标签", topN);
Set<String> tagSet = redisTemplate.opsForZSet().reverseRange(TAG_KEY, 0, topN - 1);
if (tagSet == null) {
return List.of(); // 或者返回一个空的List
}
return tagSet.stream().collect(Collectors.toList());
}
}

View File

@@ -11,87 +11,66 @@ import org.springframework.stereotype.Service;
import java.util.List;
/**
* 标签服务实现类
*/
@Service
public class TagServiceImpl extends ServiceImpl<TagMapper, Tag> implements TagService {
// 使用SLF4J的LoggerFactory创建一个Logger实例
private static final Logger logger = LoggerFactory.getLogger(TagServiceImpl.class);
@Autowired
private TagMapper tagMapper;
/**
* 创建标签
* @param tag 标签实体对象
*/
@Override
public void createTag(Tag tag) {
try {
// 保存标签到数据库
save(tag);
logger.info("Tag created successfully: {}", tag);
logger.info("标签创建成功:{}", tag);
} catch (Exception e) {
logger.error("Failed to create tag: {}", tag, e);
logger.error("标签创建失败:{}", tag, e);
throw e; // 重新抛出异常以便控制器能捕获并处理
}
}
/**
* 根据ID获取标签
* @param tagId 标签ID
* @return 标签实体对象
*/
@Override
public Tag getTagById(Long tagId) {
try {
// 根据ID查询标签
return getById(tagId);
} catch (Exception e) {
logger.error("Failed to get tag by id: {}", tagId, e);
return null;
logger.error("获取标签ID{}失败", tagId, e);
throw e; // 重新抛出异常
}
}
/**
* 更新标签信息
* @param tagId 标签ID
* @param tag 更新后的标签实体对象
*/
@Override
public void updateTag(Long tagId, Tag tag) {
try {
// 设置标签ID并更新标签信息
tag.setTagId(tagId);
updateById(tag);
logger.info("Tag updated successfully: {}", tag);
logger.info("标签更新成功:{}", tag);
} catch (Exception e) {
logger.error("Failed to update tag with id {}: {}", tagId, tag, e);
logger.error("更新标签ID{}失败", tagId, e);
throw e; // 重新抛出异常
}
}
/**
* 删除标签
* @param tagId 标签ID
*/
@Override
public void deleteTag(Long tagId) {
try {
// 根据ID删除标签
removeById(tagId);
logger.info("Tag deleted successfully with id: {}", tagId);
logger.info("标签删除成功ID{}", tagId);
} catch (Exception e) {
logger.error("Failed to delete tag with id: {}", tagId, e);
logger.error("删除标签ID{}失败", tagId, e);
throw e; // 重新抛出异常
}
}
@Override
public List<Tag> getTagList() {
List<Tag> tags = tagMapper.selectList(null);
if (tags != null) {
return tags;
}
return null;
try {
return tagMapper.selectList(null);
} catch (Exception e) {
logger.error("获取标签列表失败", e);
throw e; // 重新抛出异常
}
}
}

View File

@@ -0,0 +1,528 @@
package com.ivmiku.tutorial.util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* @className: RedisUtil
* @description:
* @author: sh.Liu
* @date: 2022-03-09 14:07
*/
@Component
public class RedisUtil {
@Autowired
private RedisTemplate redisTemplate;
/**
* 给一个指定的 key 值附加过期时间
*
* @param key
* @param time
* @return
*/
public boolean expire(String key, long time) {
return redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
/**
* 根据key 获取过期时间
*
* @param key
* @return
*/
public long getTime(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
/**
* 根据key 获取过期时间
*
* @param key
* @return
*/
public boolean hasKey(String key) {
return redisTemplate.hasKey(key);
}
/**
* 移除指定key 的过期时间
*
* @param key
* @return
*/
public boolean persist(String key) {
return redisTemplate.boundValueOps(key).persist();
}
//- - - - - - - - - - - - - - - - - - - - - String类型 - - - - - - - - - - - - - - - - - - - -
/**
* 根据key获取值
*
* @param key 键
* @return 值
*/
public Object get(String key) {
return key == null ? null : redisTemplate.opsForValue().get(key);
}
/**
* 将值放入缓存
*
* @param key 键
* @param value 值
* @return true成功 false 失败
*/
public void set(String key, String value) {
redisTemplate.opsForValue().set(key, value);
}
/**
* 将值放入缓存并设置时间
*
* @param key 键
* @param value 值
* @param time 时间(秒) -1为无期限
* @return true成功 false 失败
*/
public void set(String key, String value, long time) {
if (time > 0) {
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
} else {
redisTemplate.opsForValue().set(key, value);
}
}
/**
* 批量添加 key (重复的键会覆盖)
*
* @param keyAndValue
*/
public void batchSet(Map<String, String> keyAndValue) {
redisTemplate.opsForValue().multiSet(keyAndValue);
}
/**
* 批量添加 key-value 只有在键不存在时,才添加
* map 中只要有一个key存在,则全部不添加
*
* @param keyAndValue
*/
public void batchSetIfAbsent(Map<String, String> keyAndValue) {
redisTemplate.opsForValue().multiSetIfAbsent(keyAndValue);
}
/**
* 对一个 key-value 的值进行加减操作,
* 如果该 key 不存在 将创建一个key 并赋值该 number
* 如果 key 存在,但 value 不是长整型 ,将报错
*
* @param key
* @param number
*/
public Long increment(String key, long number) {
return redisTemplate.opsForValue().increment(key, number);
}
/**
* 对一个 key-value 的值进行加减操作,
* 如果该 key 不存在 将创建一个key 并赋值该 number
* 如果 key 存在,但 value 不是 纯数字 ,将报错
*
* @param key
* @param number
*/
public Double increment(String key, double number) {
return redisTemplate.opsForValue().increment(key, number);
}
//- - - - - - - - - - - - - - - - - - - - - set类型 - - - - - - - - - - - - - - - - - - - -
/**
* 将数据放入set缓存
*
* @param key 键
* @return
*/
public void sSet(String key, String value) {
redisTemplate.opsForSet().add(key, value);
}
/**
* 获取变量中的值
*
* @param key 键
* @return
*/
public Set<Object> members(String key) {
return redisTemplate.opsForSet().members(key);
}
/**
* 随机获取变量中指定个数的元素
*
* @param key 键
* @param count 值
* @return
*/
public void randomMembers(String key, long count) {
redisTemplate.opsForSet().randomMembers(key, count);
}
/**
* 随机获取变量中的元素
*
* @param key 键
* @return
*/
public Object randomMember(String key) {
return redisTemplate.opsForSet().randomMember(key);
}
/**
* 弹出变量中的元素
*
* @param key 键
* @return
*/
public Object pop(String key) {
return redisTemplate.opsForSet().pop("setValue");
}
/**
* 获取变量中值的长度
*
* @param key 键
* @return
*/
public long size(String key) {
return redisTemplate.opsForSet().size(key);
}
/**
* 根据value从一个set中查询,是否存在
*
* @param key 键
* @param value 值
* @return true 存在 false不存在
*/
public boolean sHasKey(String key, Object value) {
return redisTemplate.opsForSet().isMember(key, value);
}
/**
* 检查给定的元素是否在变量中。
*
* @param key 键
* @param obj 元素对象
* @return
*/
public boolean isMember(String key, Object obj) {
return redisTemplate.opsForSet().isMember(key, obj);
}
/**
* 转移变量的元素值到目的变量。
*
* @param key 键
* @param value 元素对象
* @param destKey 元素对象
* @return
*/
public boolean move(String key, String value, String destKey) {
return redisTemplate.opsForSet().move(key, value, destKey);
}
/**
* 批量移除set缓存中元素
*
* @param key 键
* @param values 值
* @return
*/
public void remove(String key, Object... values) {
redisTemplate.opsForSet().remove(key, values);
}
/**
* 通过给定的key求2个set变量的差值
*
* @param key 键
* @param destKey 键
* @return
*/
public Set<Set> difference(String key, String destKey) {
return redisTemplate.opsForSet().difference(key, destKey);
}
//- - - - - - - - - - - - - - - - - - - - - hash类型 - - - - - - - - - - - - - - - - - - - -
/**
* 加入缓存
*
* @param key 键
* @param map 键
* @return
*/
public void add(String key, Map<String, String> map) {
redisTemplate.opsForHash().putAll(key, map);
}
/**
* 获取 key 下的 所有 hashkey 和 value
*
* @param key 键
* @return
*/
public Map<Object, Object> getHashEntries(String key) {
return redisTemplate.opsForHash().entries(key);
}
/**
* 验证指定 key 下 有没有指定的 hashkey
*
* @param key
* @param hashKey
* @return
*/
public boolean hashKey(String key, String hashKey) {
return redisTemplate.opsForHash().hasKey(key, hashKey);
}
/**
* 获取指定key的值string
*
* @param key 键
* @param key2 键
* @return
*/
public String getMapString(String key, String key2) {
return redisTemplate.opsForHash().get("map1", "key1").toString();
}
/**
* 获取指定的值Int
*
* @param key 键
* @param key2 键
* @return
*/
public Integer getMapInt(String key, String key2) {
return (Integer) redisTemplate.opsForHash().get("map1", "key1");
}
/**
* 弹出元素并删除
*
* @param key 键
* @return
*/
public String popValue(String key) {
return redisTemplate.opsForSet().pop(key).toString();
}
/**
* 删除指定 hash 的 HashKey
*
* @param key
* @param hashKeys
* @return 删除成功的 数量
*/
public Long delete(String key, String... hashKeys) {
return redisTemplate.opsForHash().delete(key, hashKeys);
}
/**
* 给指定 hash 的 hashkey 做增减操作
*
* @param key
* @param hashKey
* @param number
* @return
*/
public Long increment(String key, String hashKey, long number) {
return redisTemplate.opsForHash().increment(key, hashKey, number);
}
/**
* 给指定 hash 的 hashkey 做增减操作
*
* @param key
* @param hashKey
* @param number
* @return
*/
public Double increment(String key, String hashKey, Double number) {
return redisTemplate.opsForHash().increment(key, hashKey, number);
}
/**
* 获取 key 下的 所有 hashkey 字段
*
* @param key
* @return
*/
public Set<Object> hashKeys(String key) {
return redisTemplate.opsForHash().keys(key);
}
/**
* 获取指定 hash 下面的 键值对 数量
*
* @param key
* @return
*/
public Long hashSize(String key) {
return redisTemplate.opsForHash().size(key);
}
//- - - - - - - - - - - - - - - - - - - - - list类型 - - - - - - - - - - - - - - - - - - - -
/**
* 在变量左边添加元素值
*
* @param key
* @param value
* @return
*/
public void leftPush(String key, Object value) {
redisTemplate.opsForList().leftPush(key, value);
}
/**
* 获取集合指定位置的值。
*
* @param key
* @param index
* @return
*/
public Object index(String key, long index) {
return redisTemplate.opsForList().index("list", 1);
}
/**
* 获取指定区间的值。
*
* @param key
* @param start
* @param end
* @return
*/
public List<Object> range(String key, long start, long end) {
return redisTemplate.opsForList().range(key, start, end);
}
/**
* 把最后一个参数值放到指定集合的第一个出现中间参数的前面,
* 如果中间参数值存在的话。
*
* @param key
* @param pivot
* @param value
* @return
*/
public void leftPush(String key, String pivot, String value) {
redisTemplate.opsForList().leftPush(key, pivot, value);
}
/**
* 向左边批量添加参数元素。
*
* @param key
* @param values
* @return
*/
public void leftPushAll(String key, String... values) {
// redisTemplate.opsForList().leftPushAll(key,"w","x","y");
redisTemplate.opsForList().leftPushAll(key, values);
}
/**
* 向集合最右边添加元素。
*
* @param key
* @param value
* @return
*/
public void leftPushAll(String key, String value) {
redisTemplate.opsForList().rightPush(key, value);
}
/**
* 向左边批量添加参数元素。
*
* @param key
* @param values
* @return
*/
public void rightPushAll(String key, String... values) {
//redisTemplate.opsForList().leftPushAll(key,"w","x","y");
redisTemplate.opsForList().rightPushAll(key, values);
}
/**
* 向已存在的集合中添加元素。
*
* @param key
* @param value
* @return
*/
public void rightPushIfPresent(String key, Object value) {
redisTemplate.opsForList().rightPushIfPresent(key, value);
}
/**
* 向已存在的集合中添加元素。
*
* @param key
* @return
*/
public long listLength(String key) {
return redisTemplate.opsForList().size(key);
}
/**
* 移除集合中的左边第一个元素。
*
* @param key
* @return
*/
public void leftPop(String key) {
redisTemplate.opsForList().leftPop(key);
}
/**
* 移除集合中左边的元素在等待的时间里,如果超过等待的时间仍没有元素则退出。
*
* @param key
* @return
*/
public void leftPop(String key, long timeout, TimeUnit unit) {
redisTemplate.opsForList().leftPop(key, timeout, unit);
}
/**
* 移除集合中右边的元素。
*
* @param key
* @return
*/
public void rightPop(String key) {
redisTemplate.opsForList().rightPop(key);
}
/**
* 移除集合中右边的元素在等待的时间里,如果超过等待的时间仍没有元素则退出。
*
* @param key
* @return
*/
public void rightPop(String key, long timeout, TimeUnit unit) {
redisTemplate.opsForList().rightPop(key, timeout, unit);
}
}

View File

@@ -4,6 +4,9 @@ wx.miniapp.configs[0].secret=989f155fcc3aee616568473faf1b1d3b
spring.data.redis.host=localhost
spring.data.redis.port=6379
spring.data.redis.database=0
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.application.name=community
@@ -24,3 +27,7 @@ minio.accessKey=minio_root
minio.secretKey=minio_123456
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

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ivmiku.tutorial.mapper.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

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ivmiku.tutorial.mapper.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

@@ -10,18 +10,20 @@
<result property="communityId" column="community_id" jdbcType="BIGINT"/>
<result property="title" column="title" jdbcType="VARCHAR"/>
<result property="content" column="content" jdbcType="VARCHAR"/>
<result property="videoUrl" column="video_url" jdbcType="VARCHAR"/> <!-- 新增字段 -->
<result property="imageUrls" column="image_urls" jdbcType="VARCHAR"/> <!-- 新增字段 -->
<result property="videoUrl" column="video_url" jdbcType="VARCHAR"/>
<result property="imageUrls" column="image_urls" jdbcType="VARCHAR"/>
<result property="isDeleted" column="is_deleted" jdbcType="TINYINT"/>
<result property="isOfficial" column="is_official" jdbcType="TINYINT"/> <!-- 新增字段 -->
<result property="isOfficial" column="is_official" jdbcType="TINYINT"/>
<result property="isPublic" column="is_public" jdbcType="TINYINT"/>
<result property="location" column="location" jdbcType="VARCHAR"/>
<result property="createdAt" column="created_at" jdbcType="TIMESTAMP"/>
<result property="updatedAt" column="updated_at" jdbcType="TIMESTAMP"/>
</resultMap>
<sql id="Base_Column_List">
post_id, user_openid, community_id, title, content,
video_url, image_urls, <!-- 新增字段 -->
is_deleted, is_official, created_at, updated_at
video_url, image_urls,
is_deleted, is_official, is_public, location, created_at, updated_at
</sql>
<!-- 查询指定帖子的所有评论 -->
@@ -36,12 +38,12 @@
<insert id="insertPost" parameterType="com.ivmiku.tutorial.entity.Post">
INSERT INTO post (
post_id, user_openid, community_id, title, content,
video_url, image_urls, <!-- 新增字段 -->
is_deleted, is_official, created_at, updated_at
video_url, image_urls,
is_deleted, is_official, is_public, location, created_at, updated_at
) VALUES (
#{postId}, #{userOpenid}, #{communityId}, #{title}, #{content},
#{videoUrl}, #{imageUrls}, <!-- 新增字段 -->
#{isDeleted}, #{isOfficial}, #{createdAt}, #{updatedAt}
#{videoUrl}, #{imageUrls},
#{isDeleted}, #{isOfficial}, #{is_public}, #{location}, #{createdAt}, #{updatedAt}
)
</insert>
@@ -53,10 +55,12 @@
community_id = #{communityId},
title = #{title},
content = #{content},
video_url = #{videoUrl}, <!-- 新增字段 -->
image_urls = #{imageUrls}, <!-- 新增字段 -->
video_url = #{videoUrl},
image_urls = #{imageUrls},
is_deleted = #{isDeleted},
is_official = #{isOfficial},
is_public = #{is_public},
location = #{location},
created_at = #{createdAt},
updated_at = #{updatedAt}
WHERE post_id = #{postId}
@@ -72,9 +76,9 @@
<select id="getTagPostList" resultType="com.ivmiku.tutorial.entity.Post">
SELECT p.post_id, p.user_openid, p.community_id, p.title, p.content,
p.is_deleted, p.is_official, p.created_at, p.updated_at
p.is_deleted, p.is_official, p.is_public, p.location, p.created_at, p.updated_at
FROM post p, posttag pt, tag t
WHERE p.post_id = pt.post_id AND pt.tag_id = t.tag_id AND t.tag_id = #{tagId} AND p.is_deleted = 0
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>
</mapper>

View File

@@ -29,6 +29,7 @@
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>3.5.7</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
@@ -98,5 +99,15 @@
<artifactId>tencentcloud-sdk-java-ocr</artifactId>
<version>3.1.1076</version>
</dependency>
<dependency>
<groupId>com.tencentcloudapi</groupId>
<artifactId>tencentcloud-sdk-java-tts</artifactId>
<version>3.1.1076</version>
</dependency>
<dependency>
<groupId>com.tencentcloudapi</groupId>
<artifactId>tencentcloud-sdk-java-asr</artifactId>
<version>3.1.1083</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,33 @@
package com.ivmiku.tutorial.config;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.filter.SaServletFilter;
import cn.dev33.satoken.same.SaSameUtil;
import cn.dev33.satoken.util.SaResult;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* Sa-Token 权限认证 配置类
*/
@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
// 注册 Sa-Token 全局过滤器
@Bean
public SaServletFilter getSaServletFilter() {
return new SaServletFilter()
.addInclude("/**")
.addExclude("/favicon.ico")
.setAuth(obj -> {
// 校验 Same-Token 身份凭证 —— 以下两句代码可简化为SaSameUtil.checkCurrentRequestToken();
String token = SaHolder.getRequest().getHeader(SaSameUtil.SAME_TOKEN);
SaSameUtil.checkToken(token);
})
.setError(e -> {
return SaResult.error(e.getMessage());
})
;
}
}

View File

@@ -0,0 +1,27 @@
package com.ivmiku.tutorial.controller;
import cn.dev33.satoken.annotation.SaCheckLogin;
import com.ivmiku.tutorial.response.Result;
import com.ivmiku.tutorial.service.AssistantService;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/assistant")
@SaCheckLogin
public class AssistantController {
@Resource
private AssistantService assistantService;
@GetMapping("/response")
public Object getResponse(@RequestParam String input) {
Map<String, Object> map = assistantService.getResponse(input);
if (map == null) {
return Result.error("请求出错");
}
return Result.ok(map);
}
}

View File

@@ -34,6 +34,9 @@ public class NavigateController {
String userId = (String) StpUtil.getLoginId();
if (!origin.isEmpty() && !destination.isEmpty()) {
Map<String, Object> route = navigateService.getRoute(origin, destination);
if (route == null) {
return JSON.toJSON(Result.error("路线规划失败!"));
}
List<RouteStep> stepsList = (List<RouteStep>) route.get("steps");
STEPS_MAP.put(userId, stepsList);
Map<String, Object> map = new HashMap<>();
@@ -50,13 +53,24 @@ public class NavigateController {
map.put("step", STEPS_MAP.get(userId).get(step-1));
return JSON.toJSON(Result.ok(map));
}
return JSON.toJSON(Result.error("非法的请求参数"));
return Result.error("非法的请求参数");
}
@PostMapping("/ticket")
public Object scanTicket(@RequestPart MultipartFile file) throws IOException {
BufferedImage image = ImageIO.read(file.getInputStream());
Map<String, Object> map = navigateService.scanTicket(image);
return JSON.toJSON(Result.ok(map));
return Result.ok(map);
}
@GetMapping("/geocode")
public Object getGeoCode(@RequestParam String address, @RequestParam(defaultValue = "") String city) {
String geoCode = navigateService.getGeoCode(address, city);
if (geoCode == null) {
return JSON.toJSON(Result.error("未获取到有效信息"));
}
Map<String, Object> map = new HashMap<>();
map.put("geocode", geoCode);
return Result.ok(map);
}
}

View File

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

View File

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

@@ -0,0 +1,157 @@
package com.ivmiku.tutorial.service;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson2.JSONArray;
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.tencentcloudapi.asr.v20190614.AsrClient;
import com.tencentcloudapi.asr.v20190614.models.SentenceRecognitionRequest;
import com.tencentcloudapi.asr.v20190614.models.SentenceRecognitionResponse;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.tts.v20190823.TtsClient;
import com.tencentcloudapi.tts.v20190823.models.TextToVoiceRequest;
import com.tencentcloudapi.tts.v20190823.models.TextToVoiceResponse;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class AssistantService {
@Resource
private GuidanceMapper guidanceMapper;
private final String auth = "bad1f6cad39a4c26aa9fe9e4324e096f:ZDczMDIwOTg3NjlhODdmYWVjYTY0YjM1";
private final String secretId = "AKID09INNYxYEFFJH3g9VhljVF3qbDiFdx50";
private final String secretKey = "KajjcNyNaaUCqQroqpzNoMtTHNj4Lbil";
public Map<String, Object> getAiResponse(String userInput) {
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", userInput);
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);
JSONObject content = message.getJSONObject("message");
Map<String, Object> map = new HashMap<>();
map.put("content", content.get("content"));
return map;
}
public String textToSpeech(String content) {
try{
Credential cred = new Credential(secretId, secretKey);
HttpProfile httpProfile = new HttpProfile();
httpProfile.setEndpoint("tts.tencentcloudapi.com");
ClientProfile clientProfile = new ClientProfile();
clientProfile.setHttpProfile(httpProfile);
TtsClient client = new TtsClient(cred, "ap-shanghai", clientProfile);
TextToVoiceRequest req = new TextToVoiceRequest();
req.setText(content);
req.setSessionId(SnowflakeUtil.getNext());
req.setVoiceType(101006L);
TextToVoiceResponse resp = client.TextToVoice(req);
return resp.getAudio();
} catch (TencentCloudSDKException e) {
throw new RuntimeException(e);
}
}
public String speechRecognition(String content, Integer length) {
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();
req.setEngSerViceType("16k_zh");
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) {
Map<String, Object> result = new HashMap<>();
String tag = extractTag(query);
String content;
content = searchGuidance(tag);
if (content != null) {
result.put("content", content);
return result;
}
return getAiResponse(query);
}
}

View File

@@ -36,7 +36,11 @@ public class NavigateService {
.execute();
String result = response.body();
response.close();
JSONObject route = JSONObject.parseObject(JSONObject.parseObject(result).getString("route"));
JSONObject resultObj = JSONObject.parseObject(result);
if (resultObj.getInteger("status")==0) {
return null;
}
JSONObject route = JSONObject.parseObject(resultObj.getString("route"));
JSONArray paths = JSONArray.parseArray(route.getString("paths"));
JSONObject path = paths.getJSONObject(0);
String distance = path.getString("distance");
@@ -81,4 +85,25 @@ public class NavigateService {
}
return result;
}
public String getGeoCode(String address, String city) {
Map<String, Object> params = new HashMap<>();
params.put("key", key);
params.put("address", address);
if (!city.isEmpty()) {
params.put("city", city);
}
HttpResponse response = HttpRequest.get("https://restapi.amap.com/v3/geocode/geo")
.form(params)
.execute();
String result = response.body();
response.close();
JSONObject resultObj = JSONObject.parseObject(result);
if (resultObj.getInteger("status")==0) {
return null;
}
JSONArray array = resultObj.getJSONArray("geocodes");
JSONObject location = array.getJSONObject(0);
return location.getString("location");
}
}

View File

@@ -0,0 +1,14 @@
package com.ivmiku.tutorial.utils;
import cn.hutool.core.lang.generator.SnowflakeGenerator;
public class SnowflakeUtil {
private static SnowflakeGenerator generator;
static {
generator = new SnowflakeGenerator();
}
public static String getNext() {
return String.valueOf(generator.next());
}
}

12
pom.xml
View File

@@ -25,7 +25,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<hutool.version>5.8.22</hutool.version>
<lombok.version>1.18.30</lombok.version>
<mybatis.springboot.version>3.5.6</mybatis.springboot.version>
<!-- <mybatis.springboot.version>3.5.6</mybatis.springboot.version>-->
<mysql.version>8.0.28</mysql.version>
<mapper.version>4.2.3</mapper.version>
<fastjson2.version>2.0.40</fastjson2.version>
@@ -110,11 +110,11 @@
<scope>import</scope>
</dependency>
<!--SpringBoot集成mybatis-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>${mybatis.springboot.version}</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>com.baomidou</groupId>-->
<!-- <artifactId>mybatis-plus-spring-boot3-starter</artifactId>-->
<!-- <version>${mybatis.springboot.version}</version>-->
<!-- </dependency>-->
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<!-- <dependency>-->

View File

@@ -28,7 +28,8 @@
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.7</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
@@ -116,6 +117,14 @@
<artifactId>commons</artifactId>
<version>1.0-SNAPSHOT</version>
</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>
<build>

View File

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

@@ -0,0 +1,27 @@
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 FanoutExchange exchange1() {
return new FanoutExchange("exchange1",true, false);
}
@Bean
public Binding binding1() {
return BindingBuilder.bind(queue1()).to(exchange1());
}
}

View File

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

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

@@ -0,0 +1,39 @@
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("/api/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

@@ -0,0 +1,42 @@
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("/api/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

@@ -0,0 +1,142 @@
package com.ivmiku.tutorial.controller;
import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.fastjson2.JSON;
import com.ivmiku.tutorial.entity.Message;
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.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
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.Objects;
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 {
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) {
session.getBasicRemote().sendText(JSON.toJSONString(msg));
}
}
@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, ParseException {
Message msg = JSON.parseObject(message, Message.class);
if (sessionMap.containsKey(msg.getToId())) {
sessionMap.get(msg.getToId()).getBasicRemote().sendText(JSON.toJSONString(msg));
}
}
}

View File

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

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

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

View File

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

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

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

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

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

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

View File

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

View File

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

View File

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

View File

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

@@ -0,0 +1,236 @@
package com.ivmiku.tutorial.service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ivmiku.tutorial.entity.ChatId;
import com.ivmiku.tutorial.entity.Message;
import com.ivmiku.tutorial.mapper.ChatIdMapper;
import com.ivmiku.tutorial.mapper.MessageMapper;
import com.ivmiku.tutorial.utils.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* @author Aurora
*/
@Service
public class MessageService {
@Autowired
private MessageMapper messageMapper;
@Autowired
private ChatIdMapper chatIdMapper;
@Autowired
private RedisUtil redisUtil;
/**
* 获取会话id
* @param user1Id 用户1id
* @param user2Id 用户2id
* @return 查询结果
*/
public String getChatId(String user1Id, String user2Id) {
if (Objects.equals(user1Id, "public") || Objects.equals(user2Id, "public")) {
return "0";
}
String id1, id2;
if (user1Id.compareTo(user2Id) < 0) {
id1 = user1Id;
id2 = user2Id;
} else {
id1 = user2Id;
id2 = user1Id;
}
QueryWrapper<ChatId> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("user1_id", id1);
queryWrapper.eq("user2_id", id2);
ChatId chatId = chatIdMapper.selectOne(queryWrapper);
if (chatId == null) {
chatId = new ChatId();
chatId.setUser1Id(id1);
chatId.setUser2Id(id2);
chatIdMapper.insert(chatId);
}
return chatIdMapper.selectOne(queryWrapper).getId();
}
/**
* 聊天记录写redis
* @param msg 要写入的信息
* @throws ParseException
*/
@Async
public void insertToRedis(Message msg) throws ParseException {
if (!(msg.getMessage().length() >1000)) {
if (redisUtil.getZsetSize("history:" + msg.getChatId()) >= 50) {
redisUtil.zsetRightPop("history:" + msg.getChatId());
}
redisUtil.zsetAdd("history:" + msg.getChatId(), msg);
redisUtil.setExpireTime("history:" + msg.getChatId());
}
}
/**
* 聊天记录写入mysql
* @param msg 要写入的消息
*/
@Async
public void insertToMysql(Message msg) {
if (!(msg.getMessage().length() >1000)) {
messageMapper.insert(msg);
}
}
/**
* 未读消息写入redis
* @param userId 用户id
* @param msg 未读消息
*/
@Async
public void insertUnreadMsg(String userId, Message msg) {
redisUtil.listAdd("unread:" + userId, msg);
}
/**
* 获取未读消息列表
* @param userId 用户id
* @return 查询结果
*/
public List<Message> getUnreadMsg(String userId) {
List<Message> result = redisUtil.listGet("unread:" + userId, 0, -1);
redisUtil.listClear(userId);
return result;
}
/**
* 从数据库获取聊天记录
* @param chatId 会话id
* @param current 分页参数
* @param size 分页参数
* @return 返回的查询结果
*/
public List<Message> getChatHistoryFromDB(String chatId, int current, int size) {
QueryWrapper<Message> queryWrapper = new QueryWrapper<>();
Page<Message> page = new Page<>(current, size);
queryWrapper.eq("chat_id", chatId);
queryWrapper.orderByDesc("date");
return messageMapper.selectPage(page, queryWrapper).getRecords();
}
/**
* 从数据库获取聊天记录,查询一定范围内
* @param chatId 会话id
* @param current 分页参数
* @param size 分页参数
* @param startDate 开始日期
* @param endDate 结束日期
* @return 返回的查询结果
*/
public List<Message> getChatHistoryFromDBByDate(String chatId, int current, int size, String startDate, String endDate) {
QueryWrapper<Message> queryWrapper = new QueryWrapper<>();
queryWrapper.between("date", startDate, endDate);
Page<Message> page = new Page<>(current, size);
queryWrapper.eq("chat_id", chatId);
queryWrapper.orderByDesc("date");
return messageMapper.selectPage(page, queryWrapper).getRecords();
}
/**
* redis获取聊天记录
* @param chatId 会话id
* @param s 开始
* @param e 结束
* @return 查询结果
*/
public List<Message> getChatHistoryFromRedis(String chatId, int s, int e) {
return redisUtil.zsetGet("history:" + chatId, s, e);
}
/**
* 查询聊天记录
* @param user1Id 用户1id
* @param user2Id 用户2id
* @param page 分页参数
* @param size 分页参数
* @return 查询结果
* @throws ParseException
*/
public List<Message> getChatHistory(String user1Id, String user2Id, int page, int size) throws ParseException {
int start = page * size - size;
int end = page * size - 1;
String chatId = getChatId(user1Id, user2Id);
loadCache(chatId);
List<Message> result = new ArrayList<>(redisUtil.zsetGet("history:" + chatId, start, end));
if ((end -start + 1) == result.size()) {
return result;
}
int redisSize = result.size();
List<Message> dbList = getChatHistoryFromDB(chatId, ((end - result.size()) / size) + 1, size);
result.addAll(dbList.subList(redisSize, dbList.size()));
redisUtil.refreshExpire("history:" + chatId);
return result;
}
/**
* 在一定时间范围内查询聊天记录
* @param user1Id 用户1id
* @param user2Id 用户2id
* @param startDate 开始日期
* @param endDate 结束日期
* @param page 分页参数
* @param size 分页参数
* @return 查询结果
* @throws ParseException
*/
public List<Message> getChatHistoryByDate(String user1Id, String user2Id, String startDate, String endDate, int page, int size) throws ParseException {
int start = page * size - size;
int end = page * size - 1;
String chatId = getChatId(user1Id, user2Id);
loadCache(chatId);
List<Message> result = new ArrayList<>(redisUtil.zsetGetByDate("history:" + chatId, startDate, endDate, start, size));
redisUtil.refreshExpire("history:" + chatId);
if (result.size() == (end - start + 1)) {
return result;
}
int redisSize = result.size();
List<Message> dbList = getChatHistoryFromDBByDate(chatId, ((end - result.size()) / size) + 1, size, startDate, endDate).subList(result.size(), size);
result.addAll(dbList.subList(redisSize, dbList.size()));
return result;
}
/**
* 获取会话列表
* @param userId 用户id
* @param current 分页参数
* @param size 分页参数
* @return 查询结果
*/
public List<ChatId> getChatList(String userId, int current, int size) {
QueryWrapper<ChatId> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("user1_id", userId).or().eq("user2_id", userId);
queryWrapper.orderByDesc("id");
Page<ChatId> page = new Page<>(current, size);
return chatIdMapper.selectPage(page, queryWrapper).getRecords();
}
/**
* 加载聊天记录到redis
* @param chatId 会话id
* @throws ParseException
*/
public void loadCache(String chatId) throws ParseException {
if (!redisUtil.ifExist("history:" + chatId)) {
List<Message> list = getChatHistoryFromDB(chatId, 1, 20);
for (Message message : list) {
insertToRedis(message);
}
}
}
}

View File

@@ -0,0 +1,120 @@
package com.ivmiku.tutorial.service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ivmiku.tutorial.entity.*;
import com.ivmiku.tutorial.mapper.BlackListMapper;
import com.ivmiku.tutorial.mapper.FriendMapper;
import com.ivmiku.tutorial.mapper.SubscribeMapper;
import com.ivmiku.tutorial.utils.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
/**
* @author Aurora
*/
@Service
public class RelationService {
@Autowired
private BlackListMapper blackListMapper;
@Autowired
private FriendMapper friendMapper;
@Autowired
private RedisUtil redisUtil;
@Autowired
private SubscribeMapper subscribeMapper;
@Autowired
private UserService userService;
/**
* 屏蔽用户
* @param userId 用户id
* @param toIgnore 要屏蔽的用户id
*/
public void IgnoreUser(String userId, String toIgnore) {
blackListMapper.insert(new IgnoreUser(userId, toIgnore));
if (redisUtil.ifExist("blacklist:" + userId)) {
redisUtil.listAdd("blacklist:" + userId, toIgnore);
}
}
/**
* 查询用户是否屏蔽了该用户
* @param userId 用户id
* @param ignoreId 要查询的id
* @return 查询结果
*/
public boolean ifIgnored(String userId, String ignoreId) {
loadCache(userId);
List<String> blackList = redisUtil.getStringList("blacklist:" + userId, 0, -1);
redisUtil.refreshExpire("blacklist:" + userId);
return blackList.contains(ignoreId);
}
/**
* 加载缓存
* @param userId 用户id
*/
public void loadCache(String userId) {
if (!redisUtil.ifExist("blacklist:" + userId)) {
QueryWrapper<IgnoreUser> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("user_id", userId);
List<IgnoreUser> list = blackListMapper.selectList(queryWrapper);
List<String> result = new ArrayList<>();
if (list != null) {
for (IgnoreUser object : list) {
result.add(object.getToIgnore());
}
}
for (String toIgnore : result) {
redisUtil.listAdd("blacklist:" + userId, toIgnore);
}
redisUtil.setExpireTime("blacklist:" + userId);
}
}
public void subscribe(String id, String toId) {
Subscribe subscribe = new Subscribe();
subscribe.setId(Long.valueOf(id));
subscribe.setSubId(Long.valueOf(toId));
subscribeMapper.insert(subscribe);
}
public List<SubUser> getFanList(String userId, int page, int size) {
List<SubUser> list = new ArrayList<>();
QueryWrapper<Subscribe> queryWrapper = new QueryWrapper<>();
Page<Subscribe> pager = new Page<>(page, size);
queryWrapper.eq("sub_id", userId);
List<Subscribe> array = subscribeMapper.selectPage(pager, queryWrapper).getRecords();
for (Subscribe subscribe : array) {
String queryId = String.valueOf(subscribe.getId());
User user = userService.selectUserById(queryId);
SubUser subUser = SubUser.setUser(user);
list.add(subUser);
}
return list;
}
public List<SubUser> getSubList(String userId, int page, int size) {
List<SubUser> list = new ArrayList<>();
QueryWrapper<Subscribe> queryWrapper = new QueryWrapper<>();
Page<Subscribe> pager = new Page<>(page, size);
queryWrapper.eq("id", userId);
List<Subscribe> array = subscribeMapper.selectPage(pager, queryWrapper).getRecords();
for (Subscribe subscribe : array) {
String queryId = String.valueOf(subscribe.getSubId());
User user = userService.selectUserById(queryId);
SubUser subUser = SubUser.setUser(user);
list.add(subUser);
}
return list;
}
}

View File

@@ -0,0 +1,16 @@
package com.ivmiku.tutorial.service;
import com.ivmiku.tutorial.entity.User;
import com.ivmiku.tutorial.mapper.UserMapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Resource
private UserMapper userMapper;
public User selectUserById(String id) {
return userMapper.selectById(id);
}
}

View File

@@ -0,0 +1,43 @@
package com.ivmiku.tutorial.utils;
import jakarta.annotation.PostConstruct;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
/**
* @author Aurora
*/
public class DateUtil {
/**
* 获取当前时间
* @return 当前时间字符串
*/
public static String getCurrentTime() {
Date date = new Date();
SimpleDateFormat ft = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return ft.format(date);
}
/**
* 转换为时间戳
* @param time 时间字符串
* @return 时间戳
* @throws ParseException
*/
public static long toTimeSig(String time) throws ParseException {
SimpleDateFormat ft = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = ft.parse(time);
return date.getTime();
}
/**
* 设置当前时区GMT+8
*/
@PostConstruct
public void setTimeZone() {
TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));
}
}

View File

@@ -0,0 +1,36 @@
package com.ivmiku.tutorial.utils;
import com.ivmiku.tutorial.service.RelationService;
import org.springframework.stereotype.Component;
/**
* 敏感词检测
* @author Aurora
*/
@Component
public class MessageUtil {
private static final String[] SENSITIVE = {"你妈", "你妈逼的"};
private static RelationService relationService = null;
public MessageUtil(RelationService relationService) {
MessageUtil.relationService = relationService;
}
/**
* 查看发送的信息是否含有敏感词
* @param message 要发送的信息
* @return 检查结果
*/
public static boolean checkMessage(String message) {
if (message != null) {
for(String keyword : SENSITIVE) {
if (message.contains(keyword)){
return true;
}
}
}
return false;
}
}

View File

@@ -1,9 +1,18 @@
package com.ivmiku.tutorial.utils;
import com.alibaba.fastjson2.JSON;
import com.ivmiku.tutorial.entity.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* @author Aurora
*/
@@ -12,11 +21,97 @@ public class RedisUtil {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
public void insertKey(String userId, String sessionKey) {
redisTemplate.opsForValue().set("sessionkey:" + userId, sessionKey);
public void listAdd(String key, Object value) {
redisTemplate.opsForList().leftPush(key, value);
}
public String getKey(String userId) {
return (String) redisTemplate.opsForValue().get("sessionkey:" + userId);
public List<Message> listGet(String key, int s, int e) {
List<Object> list = redisTemplate.opsForList().range(key, s, e);
List<Message> result = new ArrayList<>();
if (list != null) {
for (Object json : list) {
result.add(JSON.parseObject(JSON.toJSONString(json), Message.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 zsetAdd(String key, Message value) throws ParseException {
redisTemplate.opsForZSet().add(key, value, DateUtil.toTimeSig(value.getDate()));
}
public List<Message> zsetGet(String key, int s, int e) {
Set<Object> list = redisTemplate.opsForZSet().reverseRange(key, s, e);
List<Message> result = new ArrayList<>();
if (list != null) {
for (Object json : list) {
result.add(JSON.parseObject(JSON.toJSONString(json), Message.class));
}
}
return result;
}
public Long getzsetSize(String key) {
return redisTemplate.opsForZSet().size(key);
}
public List<Message> zsetGetByDate(String key, String startDate, String endDate, int offset, int count) throws ParseException {
Set<Object> list = redisTemplate.opsForZSet().reverseRangeByScore(key, DateUtil.toTimeSig(startDate), DateUtil.toTimeSig(endDate), offset, count);
List<Message> result = new ArrayList<>();
if (list != null) {
for (Object json : list) {
result.add(JSON.parseObject(JSON.toJSONString(json), Message.class));
}
}
return result;
}
public Message zsetRightPop(String key) {
return JSON.parseObject(JSON.toJSONString(Objects.requireNonNull(redisTemplate.opsForZSet().popMin(key)).getValue()), Message.class);
}
public Long getZsetSize(String key) {
return redisTemplate.opsForZSet().size(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;
}
}