Compare commits
18 Commits
5dd7f7193f
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
17a52ed471 | ||
|
|
b987c11cd1 | ||
|
|
62a521388d | ||
|
|
bda83a1bfe | ||
|
|
1dc7681ac6 | ||
|
|
d4c2c87327 | ||
|
|
400a473143 | ||
|
|
262103e034 | ||
|
|
4a39ca48ee | ||
|
|
1397512e70 | ||
|
|
117ab31c00 | ||
|
|
2a36709093 | ||
|
|
ee64bca6fd | ||
|
|
6bf5fe407f | ||
|
|
22b3cdf6ae | ||
|
|
e4a343242f | ||
|
|
d5fa59170a | ||
|
|
5eb573fb9d |
@@ -0,0 +1,14 @@
|
|||||||
|
package com.ivmiku.tutorial.response;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提醒用户实体
|
||||||
|
* @author Aurora
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class AtNotifier {
|
||||||
|
private String fromId;
|
||||||
|
private String toId;
|
||||||
|
private String postId;
|
||||||
|
}
|
||||||
@@ -41,11 +41,12 @@
|
|||||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Sa-Token 权限认证,在线文档:https://sa-token.cc -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.dev33</groupId>
|
<groupId>cn.dev33</groupId>
|
||||||
<artifactId>sa-token-spring-boot-starter</artifactId>
|
<artifactId>sa-token-spring-boot3-starter</artifactId>
|
||||||
<version>1.28.0</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.minio</groupId>
|
<groupId>io.minio</groupId>
|
||||||
<artifactId>minio</artifactId>
|
<artifactId>minio</artifactId>
|
||||||
@@ -132,7 +133,6 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.dev33</groupId>
|
<groupId>cn.dev33</groupId>
|
||||||
<artifactId>sa-token-redis-jackson</artifactId>
|
<artifactId>sa-token-redis-jackson</artifactId>
|
||||||
<version>1.38.0</version>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.commons</groupId>
|
<groupId>org.apache.commons</groupId>
|
||||||
@@ -190,6 +190,14 @@
|
|||||||
<artifactId>commons</artifactId>
|
<artifactId>commons</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-amqp</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.ivmiku.tutorial.config;
|
package com.ivmiku.tutorial.config;
|
||||||
|
|
||||||
import cn.dev33.satoken.interceptor.SaAnnotationInterceptor;
|
import cn.dev33.satoken.interceptor.SaInterceptor;
|
||||||
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
@@ -11,7 +12,8 @@ public class SaTokenConfig implements WebMvcConfigurer {
|
|||||||
@Override
|
@Override
|
||||||
public void addInterceptors(InterceptorRegistry registry) {
|
public void addInterceptors(InterceptorRegistry registry) {
|
||||||
// 注册注解拦截器,并排除不需要注解鉴权的接口地址 (与登录拦截器无关)
|
// 注册注解拦截器,并排除不需要注解鉴权的接口地址 (与登录拦截器无关)
|
||||||
registry.addInterceptor(new SaAnnotationInterceptor())
|
registry.addInterceptor(new SaInterceptor(handle -> StpUtil.checkLogin()))
|
||||||
.addPathPatterns("/**");
|
.addPathPatterns("/**")
|
||||||
|
.excludePathPatterns("/swagger-ui/**");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,22 +2,23 @@ package com.ivmiku.tutorial.controller;
|
|||||||
|
|
||||||
import cn.dev33.satoken.annotation.SaCheckLogin;
|
import cn.dev33.satoken.annotation.SaCheckLogin;
|
||||||
import cn.dev33.satoken.stp.StpUtil;
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.github.pagehelper.PageInfo;
|
|
||||||
import com.ivmiku.tutorial.entity.Comment;
|
import com.ivmiku.tutorial.entity.Comment;
|
||||||
import com.ivmiku.tutorial.entity.Pages;
|
import com.ivmiku.tutorial.entity.Pages;
|
||||||
|
import com.ivmiku.tutorial.response.AtNotifier;
|
||||||
import com.ivmiku.tutorial.response.Result;
|
import com.ivmiku.tutorial.response.Result;
|
||||||
import com.ivmiku.tutorial.service.CommentService;
|
import com.ivmiku.tutorial.service.CommentService;
|
||||||
import com.ivmiku.tutorial.service.FileService;
|
import com.ivmiku.tutorial.service.FileService;
|
||||||
|
import com.ivmiku.tutorial.util.MyRedisUtil;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import org.apiguardian.api.API;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 评论控制器,用于处理评论相关的HTTP请求。
|
* 评论控制器,用于处理评论相关的HTTP请求。
|
||||||
@@ -36,6 +37,13 @@ public class CommentController {
|
|||||||
@Resource
|
@Resource
|
||||||
private FileService fileService;
|
private FileService fileService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private RabbitTemplate rabbitTemplate;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private MyRedisUtil myRedisUtil;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建评论接口。
|
* 创建评论接口。
|
||||||
*/
|
*/
|
||||||
@@ -66,6 +74,14 @@ public class CommentController {
|
|||||||
|
|
||||||
commentService.createComment(comment);
|
commentService.createComment(comment);
|
||||||
logger.info("评论创建成功,评论ID:{}", comment.getCommentId());
|
logger.info("评论创建成功,评论ID:{}", comment.getCommentId());
|
||||||
|
if (!mentionedUserId.isEmpty()) {
|
||||||
|
AtNotifier notifier = new AtNotifier();
|
||||||
|
notifier.setFromId(comment.getUserOpenid());
|
||||||
|
notifier.setToId(mentionedUserId);
|
||||||
|
notifier.setPostId(String.valueOf(comment.getCommentId()));
|
||||||
|
rabbitTemplate.convertAndSend("exchange2", "", JSON.toJSONString(notifier));
|
||||||
|
myRedisUtil.listAdd("at:" + notifier.getToId(), JSON.toJSONString(notifier));
|
||||||
|
}
|
||||||
return Result.ok(comment);
|
return Result.ok(comment);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,6 +122,14 @@ public class CommentController {
|
|||||||
|
|
||||||
commentService.createComment(reply);
|
commentService.createComment(reply);
|
||||||
logger.info("评论回复成功,评论ID:{}", reply.getCommentId());
|
logger.info("评论回复成功,评论ID:{}", reply.getCommentId());
|
||||||
|
if (!mentionedUserId.isEmpty()) {
|
||||||
|
AtNotifier notifier = new AtNotifier();
|
||||||
|
notifier.setFromId(reply.getUserOpenid());
|
||||||
|
notifier.setToId(mentionedUserId);
|
||||||
|
notifier.setPostId(String.valueOf(reply.getCommentId()));
|
||||||
|
rabbitTemplate.convertAndSend("exchange2", "", JSON.toJSONString(notifier));
|
||||||
|
myRedisUtil.listAdd("at:" + notifier.getToId(), JSON.toJSONString(notifier));
|
||||||
|
}
|
||||||
return Result.ok(reply);
|
return Result.ok(reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,7 +139,6 @@ public class CommentController {
|
|||||||
comment.setUserOpenid(StpUtil.getLoginIdAsString());
|
comment.setUserOpenid(StpUtil.getLoginIdAsString());
|
||||||
comment.setContent(content);
|
comment.setContent(content);
|
||||||
comment.setMentionedUserId(mentionedUserId);
|
comment.setMentionedUserId(mentionedUserId);
|
||||||
|
|
||||||
if ("post".equals(type)) {
|
if ("post".equals(type)) {
|
||||||
comment.setPostId(postId);
|
comment.setPostId(postId);
|
||||||
} else if ("tutorial".equals(type)) {
|
} else if ("tutorial".equals(type)) {
|
||||||
@@ -212,7 +235,7 @@ public class CommentController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取教程下的所有评论。
|
* 获取教程下的所有评论。ok
|
||||||
*
|
*
|
||||||
* @param tutorialId 帖子的唯一标识ID
|
* @param tutorialId 帖子的唯一标识ID
|
||||||
* @return 返回操作结果和评论列表
|
* @return 返回操作结果和评论列表
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.ivmiku.tutorial.controller;
|
package com.ivmiku.tutorial.controller;
|
||||||
|
|
||||||
import cn.dev33.satoken.annotation.SaCheckLogin;
|
import cn.dev33.satoken.annotation.SaCheckLogin;
|
||||||
|
import cn.dev33.satoken.annotation.SaIgnore;
|
||||||
import cn.dev33.satoken.stp.StpUtil;
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.github.pagehelper.PageInfo;
|
import com.github.pagehelper.PageInfo;
|
||||||
@@ -47,11 +48,12 @@ public class PostController {
|
|||||||
@Operation(summary = "创建帖子")
|
@Operation(summary = "创建帖子")
|
||||||
public Result createPost(@RequestParam("title") String title,
|
public Result createPost(@RequestParam("title") String title,
|
||||||
@RequestParam("content") String content,
|
@RequestParam("content") String content,
|
||||||
@RequestParam("communityId") Long communityId,
|
@RequestParam(value = "communityId") Long communityId,
|
||||||
@RequestParam("imageFiles") MultipartFile[] imageFiles,
|
@RequestParam(value = "imageFiles", required = false) MultipartFile[] imageFiles,
|
||||||
@RequestParam("videoFile") MultipartFile videoFile,
|
@RequestParam(value = "videoFile", required = false) MultipartFile videoFile,
|
||||||
@RequestParam("isPublic") Integer isPublic,
|
@RequestParam("isPublic") Integer isPublic,
|
||||||
@RequestParam("location") String location) {
|
@RequestParam(value = "location", required = false) String location) {
|
||||||
|
System.out.println("Aaa");
|
||||||
String userId = StpUtil.getLoginIdAsString();
|
String userId = StpUtil.getLoginIdAsString();
|
||||||
logger.info("用户ID:{}开始创建帖子", userId);
|
logger.info("用户ID:{}开始创建帖子", userId);
|
||||||
|
|
||||||
@@ -278,7 +280,7 @@ public class PostController {
|
|||||||
post.setTitle(title);
|
post.setTitle(title);
|
||||||
post.setContent(content);
|
post.setContent(content);
|
||||||
post.setCommunityId(communityId);
|
post.setCommunityId(communityId);
|
||||||
post.setIsDraft(0); // 0 表示草稿
|
post.setIsDraft(1); // 0 表示草稿
|
||||||
post.setLocation(location);
|
post.setLocation(location);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -321,6 +323,24 @@ public class PostController {
|
|||||||
|
|
||||||
return Result.ok(drafts);
|
return Result.ok(drafts);
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* 猜你喜欢
|
||||||
|
*/
|
||||||
|
@GetMapping("/guessYouLike")
|
||||||
|
@Operation(summary = "猜你喜欢")
|
||||||
|
public Result guessYouLike(@RequestParam("latitude") Double latitude,
|
||||||
|
@RequestParam("longitude") Double longitude) {
|
||||||
|
|
||||||
|
String userId = StpUtil.getLoginIdAsString();
|
||||||
|
String key = "search_history:" + userId;
|
||||||
|
// 获取用户的搜索历史关键词
|
||||||
|
List<String> searchHistory = redisTemplate.opsForList().range(key, 0, -1);
|
||||||
|
|
||||||
|
// 获取猜你喜欢的帖子列表
|
||||||
|
List<Post> recommendedPosts = postService.getRecommendedPosts(latitude, longitude, searchHistory);
|
||||||
|
|
||||||
|
return Result.ok(recommendedPosts);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ public class TutorialController {
|
|||||||
@RequestParam(value = "imageFile", required = false) MultipartFile imageFile,
|
@RequestParam(value = "imageFile", required = false) MultipartFile imageFile,
|
||||||
@RequestParam(value = "videoFile", required = false) MultipartFile videoFile,
|
@RequestParam(value = "videoFile", required = false) MultipartFile videoFile,
|
||||||
@RequestParam("isOfficial") Integer isOfficial) {
|
@RequestParam("isOfficial") Integer isOfficial) {
|
||||||
String userId = StpUtil.getLoginIdAsString(); // 获取 userOpenid
|
String userId = (String) StpUtil.getLoginId(); // 获取 userOpenid
|
||||||
logger.info("用户ID:{} 开始创建教程", userId);
|
logger.info("用户ID:{} 开始创建教程", userId);
|
||||||
|
|
||||||
Tutorials tutorial = new Tutorials();
|
Tutorials tutorial = new Tutorials();
|
||||||
@@ -77,7 +77,7 @@ public class TutorialController {
|
|||||||
public Result getTutorial(@PathVariable Long id) {
|
public Result getTutorial(@PathVariable Long id) {
|
||||||
Tutorials tutorial = tutorialsService.getById(id);
|
Tutorials tutorial = tutorialsService.getById(id);
|
||||||
if (tutorial != null) {
|
if (tutorial != null) {
|
||||||
return Result.ok("教程获取成功");
|
return Result.ok(tutorial);
|
||||||
}
|
}
|
||||||
return Result.error("未找到教程");
|
return Result.error("未找到教程");
|
||||||
}
|
}
|
||||||
@@ -110,7 +110,7 @@ public class TutorialController {
|
|||||||
@Operation(summary = "获取所有教程")
|
@Operation(summary = "获取所有教程")
|
||||||
public Result listTutorials() {
|
public Result listTutorials() {
|
||||||
List<Tutorials> tutorials = tutorialsService.list();
|
List<Tutorials> tutorials = tutorialsService.list();
|
||||||
return Result.ok("教程列表获取成功");
|
return Result.ok(tutorials);
|
||||||
}
|
}
|
||||||
// 根据教程标签ID获取教程列表
|
// 根据教程标签ID获取教程列表
|
||||||
@GetMapping("/listByTag/{tagId}")
|
@GetMapping("/listByTag/{tagId}")
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package com.ivmiku.tutorial.controller;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.ivmiku.tutorial.entity.UserDTO;
|
||||||
|
import com.ivmiku.tutorial.response.Result;
|
||||||
|
import com.ivmiku.tutorial.service.impl.SearchService;
|
||||||
|
import jakarta.websocket.*;
|
||||||
|
import jakarta.websocket.server.PathParam;
|
||||||
|
import jakarta.websocket.server.ServerEndpoint;
|
||||||
|
import org.springframework.beans.BeansException;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.ApplicationContextAware;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
@ServerEndpoint(value = "/search/{satoken}")
|
||||||
|
public class WebSocketServer implements ApplicationContextAware {
|
||||||
|
public static Map<String, Session> sessionMap = new ConcurrentHashMap<>();
|
||||||
|
private static ApplicationContext applicationContext;
|
||||||
|
private SearchService searchService;
|
||||||
|
|
||||||
|
@OnOpen
|
||||||
|
public void onOpen(Session session, EndpointConfig endpointConfig, @PathParam("satoken") String satoken) throws IOException {
|
||||||
|
String userId = (String) StpUtil.getLoginIdByToken(satoken);
|
||||||
|
if (userId == null) {
|
||||||
|
session.getBasicRemote().sendText("Invalid Token");
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
sessionMap.put(userId, session);
|
||||||
|
this.searchService = WebSocketServer.applicationContext.getBean(SearchService.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnClose
|
||||||
|
public void onClose(CloseReason closeReason, Session session){
|
||||||
|
sessionMap.remove(session.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnError
|
||||||
|
public void onError(Throwable throwable) throws IOException {
|
||||||
|
throwable.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnMessage
|
||||||
|
public void onMessage(String message, Session session) throws IOException {
|
||||||
|
char first = message.charAt(0);
|
||||||
|
String userId = null;
|
||||||
|
for (Map.Entry<String, Session> entry : sessionMap.entrySet()) {
|
||||||
|
if (entry.getValue().equals(session)) {
|
||||||
|
userId = entry.getKey();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (first) {
|
||||||
|
case '@' -> {
|
||||||
|
String sub = message.substring(1);
|
||||||
|
List<UserDTO> result = searchService.getUserList(sub, userId);
|
||||||
|
session.getBasicRemote().sendText(JSON.toJSONString(Result.ok(result)));
|
||||||
|
}
|
||||||
|
case '#' -> {
|
||||||
|
String sub = message.substring(1);
|
||||||
|
List<String> list = searchService.getTag(sub);
|
||||||
|
session.getBasicRemote().sendText(JSON.toJSONString(Result.ok(list)));
|
||||||
|
}
|
||||||
|
//预留给社区搜索
|
||||||
|
default -> {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||||
|
WebSocketServer.applicationContext = applicationContext;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,6 +21,7 @@ public class Comment implements Serializable {
|
|||||||
|
|
||||||
private Long postId;
|
private Long postId;
|
||||||
|
|
||||||
|
@TableField("tutorialId")
|
||||||
private Long tutorialId; // 新增字段
|
private Long tutorialId; // 新增字段
|
||||||
|
|
||||||
private String content;
|
private String content;
|
||||||
|
|||||||
@@ -44,4 +44,6 @@ public class Post implements Serializable {
|
|||||||
private Date updatedAt;
|
private Date updatedAt;
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -4,11 +4,15 @@ import com.baomidou.mybatisplus.annotation.TableId;
|
|||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
|
@TableName("user")
|
||||||
@Data
|
@Data
|
||||||
@TableName("User")
|
|
||||||
public class User {
|
public class User {
|
||||||
@TableId
|
@TableId
|
||||||
private String openid;
|
private String openid;
|
||||||
private String nickname;
|
private String nickname;
|
||||||
private String avatarUrl;
|
private String avatarUrl;
|
||||||
|
private boolean isAdmin;
|
||||||
|
private String phoneNum;
|
||||||
|
private String birthday;
|
||||||
|
private String gender;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.ivmiku.tutorial.entity;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class UserDTO {
|
||||||
|
private String nickname;
|
||||||
|
private String avatarUrl;
|
||||||
|
private String phoneNum;
|
||||||
|
private String birthday;
|
||||||
|
private String gender;
|
||||||
|
}
|
||||||
@@ -14,13 +14,16 @@ import org.apache.ibatis.annotations.Select;
|
|||||||
public interface LikeMapper extends BaseMapper<Likee> {
|
public interface LikeMapper extends BaseMapper<Likee> {
|
||||||
|
|
||||||
// 获取帖子获赞数
|
// 获取帖子获赞数
|
||||||
@Select("SELECT SUM(like_count) FROM posts WHERE user_openid = #{userOpenid}")
|
|
||||||
Long getPostLikeCount(@Param("userOpenid") String userOpenid);
|
Long getPostLikeCount(@Param("userOpenid") String userOpenid);
|
||||||
|
|
||||||
// 获取评论获赞数
|
// 获取评论获赞数
|
||||||
@Select("SELECT SUM(like_count) FROM comments WHERE user_openid = #{userOpenid}")
|
|
||||||
Long getCommentLikeCount(@Param("userOpenid") String userOpenid);
|
Long getCommentLikeCount(@Param("userOpenid") String userOpenid);
|
||||||
|
|
||||||
|
// 查询帖子被点赞的总数
|
||||||
|
Long getLikeCountByPostId(@Param("postId") Long postId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,12 @@ public interface PostMapper extends BaseMapper<Post> {
|
|||||||
List<Post> searchPosts(String keyword);
|
List<Post> searchPosts(String keyword);
|
||||||
|
|
||||||
List<Post> getTopFavoritedPosts(int limit);
|
List<Post> getTopFavoritedPosts(int limit);
|
||||||
|
|
||||||
|
List<Post> getPostsBasedOnHistoryAndHotness(Long userId, List<String> searchHistory);
|
||||||
|
|
||||||
|
|
||||||
|
@Select("SELECT * FROM post WHERE ST_Distance_Sphere(point(location_lng, location_lat), point(#{longitude}, #{latitude})) < 50000") // 50km 范围
|
||||||
|
List<Post> getPostsNearby(Double latitude, Double longitude);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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> {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.ivmiku.tutorial.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.ivmiku.tutorial.entity.User;
|
||||||
|
|
||||||
|
public interface UserMapper extends BaseMapper<User> {
|
||||||
|
}
|
||||||
@@ -31,4 +31,6 @@ public interface InteractionService {
|
|||||||
void unfavoriteOfficialTutorial(String userOpenid, Long tutorialId);
|
void unfavoriteOfficialTutorial(String userOpenid, Long tutorialId);
|
||||||
|
|
||||||
IPage<Tutorials> getFavoriteOfficialTutorials(String userOpenid, int pageNum, int pageSize);
|
IPage<Tutorials> getFavoriteOfficialTutorials(String userOpenid, int pageNum, int pageSize);
|
||||||
|
// 新增方法:根据帖子 ID 获取点赞总数
|
||||||
|
Long getLikeCountByPostId(Long postId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,4 +31,8 @@ public interface PostService extends IService<Post> {
|
|||||||
List<Post> getTopFavoritedPosts(int limit);
|
List<Post> getTopFavoritedPosts(int limit);
|
||||||
|
|
||||||
List<Post> getDraftsByUserId(String userId);
|
List<Post> getDraftsByUserId(String userId);
|
||||||
|
|
||||||
|
List<Post> getRecommendedPosts(Double latitude, Double longitude, List<String> searchHistory);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.ivmiku.tutorial.service.impl;
|
package com.ivmiku.tutorial.service.impl;
|
||||||
|
|
||||||
import cn.dev33.satoken.stp.StpUtil;
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
@@ -8,10 +9,13 @@ import com.github.pagehelper.PageHelper;
|
|||||||
import com.github.pagehelper.PageInfo;
|
import com.github.pagehelper.PageInfo;
|
||||||
import com.ivmiku.tutorial.entity.Comment;
|
import com.ivmiku.tutorial.entity.Comment;
|
||||||
import com.ivmiku.tutorial.mapper.CommentMapper;
|
import com.ivmiku.tutorial.mapper.CommentMapper;
|
||||||
|
import com.ivmiku.tutorial.response.AtNotifier;
|
||||||
import com.ivmiku.tutorial.service.CommentService;
|
import com.ivmiku.tutorial.service.CommentService;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@@ -30,6 +34,9 @@ public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> impl
|
|||||||
@Autowired
|
@Autowired
|
||||||
protected CommentMapper commentMapper;
|
protected CommentMapper commentMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private RabbitTemplate rabbitTemplate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 保存评论。
|
* 保存评论。
|
||||||
* 将评论数据保存到数据库。
|
* 将评论数据保存到数据库。
|
||||||
@@ -186,6 +193,13 @@ public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> impl
|
|||||||
reply.setMentionedUserId(mentionedUserId);
|
reply.setMentionedUserId(mentionedUserId);
|
||||||
}
|
}
|
||||||
createComment(reply);
|
createComment(reply);
|
||||||
|
if (mentionedUserId != null) {
|
||||||
|
AtNotifier notifier = new AtNotifier();
|
||||||
|
notifier.setFromId(reply.getUserOpenid());
|
||||||
|
notifier.setToId(mentionedUserId);
|
||||||
|
notifier.setPostId(String.valueOf(reply.getCommentId()));
|
||||||
|
rabbitTemplate.convertAndSend("exchange2", "", JSON.toJSONString(notifier));
|
||||||
|
}
|
||||||
|
|
||||||
logger.info("评论回复成功,评论ID:{}", reply.getCommentId());
|
logger.info("评论回复成功,评论ID:{}", reply.getCommentId());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -251,4 +251,10 @@ public class InteractionServiceImpl implements InteractionService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long getLikeCountByPostId(Long postId) {
|
||||||
|
log.info("Fetching like count for post {}", postId);
|
||||||
|
return likeMapper.getLikeCountByPostId(postId);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,17 +5,24 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
|
|||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.ivmiku.tutorial.entity.BrowingHistory;
|
import com.ivmiku.tutorial.entity.BrowingHistory;
|
||||||
import com.ivmiku.tutorial.entity.Post;
|
import com.ivmiku.tutorial.entity.Post;
|
||||||
|
import com.ivmiku.tutorial.mapper.CommentMapper;
|
||||||
|
import com.ivmiku.tutorial.mapper.FavoriteMapper;
|
||||||
|
import com.ivmiku.tutorial.mapper.LikeMapper;
|
||||||
import com.ivmiku.tutorial.mapper.PostMapper;
|
import com.ivmiku.tutorial.mapper.PostMapper;
|
||||||
import com.ivmiku.tutorial.service.BrowingHistoryService;
|
import com.ivmiku.tutorial.service.BrowingHistoryService;
|
||||||
|
import com.ivmiku.tutorial.service.InteractionService;
|
||||||
import com.ivmiku.tutorial.service.PostService;
|
import com.ivmiku.tutorial.service.PostService;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class PostServiceImpl extends ServiceImpl<PostMapper, Post> implements PostService {
|
public class PostServiceImpl extends ServiceImpl<PostMapper, Post> implements PostService {
|
||||||
@@ -25,6 +32,10 @@ public class PostServiceImpl extends ServiceImpl<PostMapper, Post> implements Po
|
|||||||
@Autowired
|
@Autowired
|
||||||
private PostMapper postMapper;
|
private PostMapper postMapper;
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
@Autowired
|
||||||
|
private InteractionService interactionService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private BrowingHistoryService browingHistoryService;
|
private BrowingHistoryService browingHistoryService;
|
||||||
|
|
||||||
@@ -193,9 +204,40 @@ public class PostServiceImpl extends ServiceImpl<PostMapper, Post> implements Po
|
|||||||
public List<Post> getDraftsByUserId(String userId) {
|
public List<Post> getDraftsByUserId(String userId) {
|
||||||
return postMapper.selectList(new LambdaQueryWrapper<Post>()
|
return postMapper.selectList(new LambdaQueryWrapper<Post>()
|
||||||
.eq(Post::getUserOpenid, userId)
|
.eq(Post::getUserOpenid, userId)
|
||||||
.eq(Post::getIsDraft, 0)); // 0 表示草稿
|
.eq(Post::getIsDraft, 1)); // 0 表示草稿
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Post> getRecommendedPosts(Double latitude, Double longitude, List<String> searchHistory) {
|
||||||
|
// 1. 根据用户当前位置计算距离(例如使用 Haversine 公式)
|
||||||
|
List<Post> nearbyPosts = postMapper.getPostsNearby(latitude, longitude);
|
||||||
|
|
||||||
|
// 2. 根据帖子热度排序
|
||||||
|
List<Post> sortedPosts = sortPostsByHeat(nearbyPosts);
|
||||||
|
|
||||||
|
// 3. 根据用户的搜索历史关键词筛选相关帖子
|
||||||
|
List<Post> matchingPosts = sortedPosts.stream()
|
||||||
|
.filter(post -> searchHistory.stream().anyMatch(keyword ->
|
||||||
|
post.getTitle().contains(keyword) || post.getContent().contains(keyword)))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
return matchingPosts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Post> sortPostsByHeat(List<Post> posts) {
|
||||||
|
// 根据帖子热度进行排序
|
||||||
|
return posts.stream()
|
||||||
|
.sorted((post1, post2) -> {
|
||||||
|
int post1Heat = calculatePostHeat(post1);
|
||||||
|
int post2Heat = calculatePostHeat(post2);
|
||||||
|
return Integer.compare(post2Heat, post1Heat); // 降序排列
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
public int calculatePostHeat(Post post) {
|
||||||
|
Long postId = post.getPostId();
|
||||||
|
return interactionService.getLikeCountByPostId(postId).intValue();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package com.ivmiku.tutorial.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.ivmiku.tutorial.entity.Subscribe;
|
||||||
|
import com.ivmiku.tutorial.entity.Tag;
|
||||||
|
import com.ivmiku.tutorial.entity.User;
|
||||||
|
import com.ivmiku.tutorial.entity.UserDTO;
|
||||||
|
import com.ivmiku.tutorial.mapper.PostTagMapper;
|
||||||
|
import com.ivmiku.tutorial.mapper.SubscribeMapper;
|
||||||
|
import com.ivmiku.tutorial.mapper.TagMapper;
|
||||||
|
import com.ivmiku.tutorial.mapper.UserMapper;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class SearchService {
|
||||||
|
@Resource
|
||||||
|
private UserMapper userMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TagMapper tagMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SubscribeMapper subscribeMapper;
|
||||||
|
|
||||||
|
public List<UserDTO> getUserList(String text, String userId) {
|
||||||
|
int len = text.length();
|
||||||
|
QueryWrapper<Subscribe> queryWrapper = new QueryWrapper<>();
|
||||||
|
queryWrapper.eq("user1_id", userId);
|
||||||
|
List<Subscribe> list = subscribeMapper.selectList(queryWrapper);
|
||||||
|
List<UserDTO> result = new ArrayList<>();
|
||||||
|
for (Subscribe subscribe : list) {
|
||||||
|
String user2Id = String.valueOf(subscribe.getSubId());
|
||||||
|
User user = userMapper.selectById(user2Id);
|
||||||
|
if (user.getNickname().substring(0, len).equals(text)) {
|
||||||
|
UserDTO userDTO = new UserDTO();
|
||||||
|
userDTO.setNickname(user.getNickname());
|
||||||
|
userDTO.setAvatarUrl(user.getAvatarUrl());
|
||||||
|
result.add(userDTO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getTag(String text) {
|
||||||
|
QueryWrapper<Tag> queryWrapper = new QueryWrapper<>();
|
||||||
|
queryWrapper.likeRight("name", text);
|
||||||
|
List<Tag> list = tagMapper.selectList(queryWrapper);
|
||||||
|
List<String> result = new ArrayList<>();
|
||||||
|
for (Tag tag : list) {
|
||||||
|
result.add(tag.getName());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
package com.ivmiku.tutorial.util;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.ivmiku.tutorial.response.AtNotifier;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Aurora
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class MyRedisUtil {
|
||||||
|
@Autowired
|
||||||
|
private RedisTemplate<String, Object> redisTemplate;
|
||||||
|
|
||||||
|
public void listAdd(String key, Object value) {
|
||||||
|
redisTemplate.opsForList().leftPush(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<AtNotifier> listGet(String key, int s, int e) {
|
||||||
|
List<Object> list = redisTemplate.opsForList().range(key, s, e);
|
||||||
|
List<AtNotifier> result = new ArrayList<>();
|
||||||
|
if (list != null) {
|
||||||
|
for (Object json : list) {
|
||||||
|
result.add(JSON.parseObject(JSON.toJSONString(json), AtNotifier.class));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void listClear(String key) {
|
||||||
|
redisTemplate.opsForList().trim(key, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getListSize(String key) {
|
||||||
|
return redisTemplate.opsForList().size(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> getKey() {
|
||||||
|
return redisTemplate.keys("history:*");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object rightPop(String key) {
|
||||||
|
return redisTemplate.opsForList().rightPop(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public void setExpireTime(String key) {
|
||||||
|
if (redisTemplate.opsForValue().getOperations().getExpire(key) > 0) {
|
||||||
|
redisTemplate.expire(key, 3, TimeUnit.DAYS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void refreshExpire(String key) {
|
||||||
|
redisTemplate.persist(key);
|
||||||
|
redisTemplate.expire(key, 3, TimeUnit.DAYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean ifExist(String key) {
|
||||||
|
return Boolean.TRUE.equals(redisTemplate.hasKey(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getStringList(String key, int s, int e) {
|
||||||
|
List<Object> list = redisTemplate.opsForList().range(key, s, e);
|
||||||
|
List<String> result = new ArrayList<>();
|
||||||
|
assert list != null;
|
||||||
|
for (Object object : list) {
|
||||||
|
result.add((String) object);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void insertKey(String openid, String sessionKey) {
|
||||||
|
redisTemplate.opsForValue().set("sessionkey:" + openid, sessionKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKey(String userId) {
|
||||||
|
return (String) redisTemplate.opsForValue().get("sessionkey:" + userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteFromList(AtNotifier message) {
|
||||||
|
String id = message.getToId();
|
||||||
|
redisTemplate.opsForList().remove("unread:" + id, 0, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
wx.miniapp.configs[0].appid=wx0d4fdb5c7bf3b12b
|
wx.miniapp.configs[0].appid=wx0d4fdb5c7bf3b12b
|
||||||
wx.miniapp.configs[0].secret=989f155fcc3aee616568473faf1b1d3b
|
wx.miniapp.configs[0].secret=989f155fcc3aee616568473faf1b1d3b
|
||||||
|
|
||||||
spring.data.redis.host=127.0.0.1
|
spring.data.redis.host=redis
|
||||||
spring.data.redis.port=6379
|
spring.data.redis.port=6379
|
||||||
spring.data.redis.database=0
|
spring.data.redis.database=0
|
||||||
|
spring.data.redis.password=Shuodedaoli114514
|
||||||
|
|
||||||
|
|
||||||
spring.application.name=community
|
spring.application.name=community
|
||||||
|
|
||||||
@@ -11,14 +13,25 @@ server.port=8073
|
|||||||
|
|
||||||
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
|
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
|
||||||
spring.datasource.username=root
|
spring.datasource.username=root
|
||||||
spring.datasource.password=123456
|
spring.datasource.password=Shuodedaoli114514
|
||||||
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/tutorial?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
|
spring.datasource.url=jdbc:mysql://mysql:3306/tutorial?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
|
||||||
|
|
||||||
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
|
spring.cloud.nacos.discovery.server-addr=nacos:8848
|
||||||
spring.cloud.nacos.discovery.enabled=true
|
spring.cloud.nacos.discovery.enabled=true
|
||||||
|
|
||||||
management.zipkin.tracing.endpoint=http://127.0.0.1:9411/api/v2/spans
|
dubbo.application.qos-enable=false
|
||||||
management.tracing.sampling.probability=1.0
|
|
||||||
|
|
||||||
|
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
|
||||||
|
|
||||||
|
minio.endpoint=120.26.243.81
|
||||||
|
minio.port=9000
|
||||||
|
minio.accessKey=minio_root
|
||||||
|
minio.secretKey=minio_123456
|
||||||
|
minio.bucketName=haixia
|
||||||
|
|
||||||
|
spring.data.redis.lettuce.pool.max-active=32
|
||||||
|
spring.data.redis.lettuce.pool.max-idle=16
|
||||||
|
spring.data.redis.lettuce.pool.min-idle=8
|
||||||
|
|
||||||
|
spring.rabbitmq.host=rabbitmq
|
||||||
|
|
||||||
|
|||||||
@@ -8,13 +8,30 @@
|
|||||||
<id property="id" column="id" jdbcType="BIGINT"/>
|
<id property="id" column="id" jdbcType="BIGINT"/>
|
||||||
<result property="userOpenid" column="user_openid" jdbcType="VARCHAR"/>
|
<result property="userOpenid" column="user_openid" jdbcType="VARCHAR"/>
|
||||||
<result property="postId" column="post_id" jdbcType="BIGINT"/>
|
<result property="postId" column="post_id" jdbcType="BIGINT"/>
|
||||||
<result property="tutorialId" column="tutorialId" jdbcType="BIGINT"/>
|
<result property="tutorialId" column="tutorial_id" jdbcType="BIGINT"/>
|
||||||
<result property="commentId" column="comment_id" jdbcType="BIGINT"/>
|
<result property="commentId" column="comment_id" jdbcType="BIGINT"/>
|
||||||
<result property="isDeleted" column="is_deleted" jdbcType="TINYINT"/>
|
<result property="isDeleted" column="is_deleted" jdbcType="TINYINT"/>
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<sql id="Base_Column_List">
|
<sql id="Base_Column_List">
|
||||||
id,user_openid,post_id,tutorialId,
|
id, user_openid, post_id, tutorial_id, comment_id, is_deleted
|
||||||
comment_id,is_deleted
|
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
|
<!-- 查询用户所有帖子的点赞总数 -->
|
||||||
|
<select id="getPostLikeCount" resultType="java.lang.Long">
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM likee
|
||||||
|
WHERE user_openid = #{userOpenid}
|
||||||
|
AND post_id IS NOT NULL
|
||||||
|
AND is_deleted = 0;
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<!-- 查询用户所有评论的点赞总数 -->
|
||||||
|
<select id="getCommentLikeCount" resultType="java.lang.Long">
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM likee
|
||||||
|
WHERE user_openid = #{userOpenid}
|
||||||
|
AND comment_id IS NOT NULL
|
||||||
|
AND is_deleted = 0;
|
||||||
|
</select>
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|||||||
@@ -86,7 +86,6 @@
|
|||||||
SELECT title
|
SELECT title
|
||||||
FROM post
|
FROM post
|
||||||
WHERE is_deleted = 0 AND is_public = 1
|
WHERE is_deleted = 0 AND is_public = 1
|
||||||
ORDER BY view_count DESC, like_count DESC
|
|
||||||
LIMIT 9
|
LIMIT 9
|
||||||
</select>
|
</select>
|
||||||
<select id="searchPosts" resultType="com.ivmiku.tutorial.entity.Post">
|
<select id="searchPosts" resultType="com.ivmiku.tutorial.entity.Post">
|
||||||
@@ -108,5 +107,11 @@
|
|||||||
ORDER BY COUNT(f.id) DESC
|
ORDER BY COUNT(f.id) DESC
|
||||||
LIMIT #{limit}
|
LIMIT #{limit}
|
||||||
</select>
|
</select>
|
||||||
|
<select id="getPostsBasedOnHistoryAndHotness" resultType="com.ivmiku.tutorial.entity.Post">
|
||||||
|
SELECT *
|
||||||
|
FROM post
|
||||||
|
WHERE content LIKE CONCAT('%', #{searchHistory}, '%')
|
||||||
|
ORDER BY hotness DESC
|
||||||
|
</select>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|||||||
@@ -47,7 +47,8 @@ public class SaTokenConfigure {
|
|||||||
"/user/register",
|
"/user/register",
|
||||||
"/swagger-resources/**",
|
"/swagger-resources/**",
|
||||||
"/v3/**",
|
"/v3/**",
|
||||||
"/swagger-ui/**")
|
"/swagger-ui/**",
|
||||||
|
"/ws/**")
|
||||||
// 鉴权方法:每次访问进入
|
// 鉴权方法:每次访问进入
|
||||||
.setAuth(obj -> {
|
.setAuth(obj -> {
|
||||||
// 登录校验 -- 拦截所有路由,并排除指定路由
|
// 登录校验 -- 拦截所有路由,并排除指定路由
|
||||||
|
|||||||
@@ -22,3 +22,11 @@ spring.cloud.gateway.routes[2].id=navigate
|
|||||||
spring.cloud.gateway.routes[2].uri=lb://navigate
|
spring.cloud.gateway.routes[2].uri=lb://navigate
|
||||||
spring.cloud.gateway.routes[2].predicates[0]=Path=/navigate/**
|
spring.cloud.gateway.routes[2].predicates[0]=Path=/navigate/**
|
||||||
spring.cloud.gateway.routes[2].filters[0]=StripPrefix=1
|
spring.cloud.gateway.routes[2].filters[0]=StripPrefix=1
|
||||||
|
|
||||||
|
spring.cloud.gateway.routes[3].id=websocket
|
||||||
|
spring.cloud.gateway.routes[3].uri=lb:ws://user
|
||||||
|
spring.cloud.gateway.routes[3].predicates[0]=Path=/chat/**
|
||||||
|
|
||||||
|
spring.cloud.gateway.routes[4].id=search
|
||||||
|
spring.cloud.gateway.routes[4].uri=lb:ws://community
|
||||||
|
spring.cloud.gateway.routes[4].predicates[0]=Path=/search/**
|
||||||
@@ -17,5 +17,15 @@ spring.cloud.gateway.routes[1].uri=lb://community
|
|||||||
spring.cloud.gateway.routes[1].predicates[0]=Path=/community/**
|
spring.cloud.gateway.routes[1].predicates[0]=Path=/community/**
|
||||||
spring.cloud.gateway.routes[1].filters[0]=StripPrefix=1
|
spring.cloud.gateway.routes[1].filters[0]=StripPrefix=1
|
||||||
|
|
||||||
#management.zipkin.tracing.endpoint=http://localhost:9411/api/v2/spans
|
spring.cloud.gateway.routes[2].id=navigate
|
||||||
#management.tracing.sampling.probability=1.0
|
spring.cloud.gateway.routes[2].uri=lb://navigate
|
||||||
|
spring.cloud.gateway.routes[2].predicates[0]=Path=/navigate/**
|
||||||
|
spring.cloud.gateway.routes[2].filters[0]=StripPrefix=1
|
||||||
|
|
||||||
|
spring.cloud.gateway.routes[3].id=websocket
|
||||||
|
spring.cloud.gateway.routes[3].uri=lb:ws://user
|
||||||
|
spring.cloud.gateway.routes[3].predicates[0]=Path=/chat/**
|
||||||
|
|
||||||
|
spring.cloud.gateway.routes[4].id=search
|
||||||
|
spring.cloud.gateway.routes[4].uri=lb:ws://community
|
||||||
|
spring.cloud.gateway.routes[4].predicates[0]=Path=/search/**
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.mysql</groupId>
|
<groupId>com.mysql</groupId>
|
||||||
<artifactId>mysql-connector-j</artifactId>
|
<artifactId>mysql-connector-j</artifactId>
|
||||||
<scope>runtime</scope>
|
<version>8.2.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.projectlombok</groupId>
|
<groupId>org.projectlombok</groupId>
|
||||||
@@ -134,6 +134,26 @@
|
|||||||
<version>1.9.1</version>
|
<version>1.9.1</version>
|
||||||
<scope>runtime</scope>
|
<scope>runtime</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
<version>3.0.13</version>
|
||||||
|
<configuration>
|
||||||
|
<mainClass>com.ivmiku.tutorial.Main8432</mainClass>
|
||||||
|
<layout>JAR</layout>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>repackage</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
</project>
|
</project>
|
||||||
@@ -1,12 +1,15 @@
|
|||||||
package com.ivmiku.tutorial.controller;
|
package com.ivmiku.tutorial.controller;
|
||||||
|
|
||||||
import cn.dev33.satoken.annotation.SaCheckLogin;
|
import cn.dev33.satoken.annotation.SaCheckLogin;
|
||||||
|
import com.ivmiku.tutorial.entity.AssistantQuery;
|
||||||
import com.ivmiku.tutorial.response.Result;
|
import com.ivmiku.tutorial.response.Result;
|
||||||
import com.ivmiku.tutorial.service.AssistantService;
|
import com.ivmiku.tutorial.service.AssistantService;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@@ -16,10 +19,10 @@ public class AssistantController {
|
|||||||
@Resource
|
@Resource
|
||||||
private AssistantService assistantService;
|
private AssistantService assistantService;
|
||||||
|
|
||||||
@GetMapping("/response")
|
@PostMapping("/response")
|
||||||
public Object getResponse(@RequestParam String input, @RequestParam int size, @RequestParam String language) {
|
public Object getResponse(@RequestBody AssistantQuery query) {
|
||||||
String userInput = assistantService.speechRecognition(input, size, language);
|
String userInput = assistantService.speechRecognition(query.getContent(), query.getSize(), query.getLanguage());
|
||||||
Map<String, Object> map = assistantService.getResponse(userInput, language);
|
Map<String, Object> map = assistantService.getResponse(userInput, query.getLanguage());
|
||||||
if (map == null) {
|
if (map == null) {
|
||||||
return Result.error("请求出错");
|
return Result.error("请求出错");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package com.ivmiku.tutorial.entity;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class AssistantQuery {
|
||||||
|
private String content;
|
||||||
|
private Integer size;
|
||||||
|
private String language;
|
||||||
|
}
|
||||||
@@ -65,10 +65,11 @@ public class AssistantService {
|
|||||||
}
|
}
|
||||||
JSONArray choices = result.getJSONArray("choices");
|
JSONArray choices = result.getJSONArray("choices");
|
||||||
JSONObject message = choices.getJSONObject(0);
|
JSONObject message = choices.getJSONObject(0);
|
||||||
return message.getString("message");
|
JSONObject content = message.getJSONObject("message");
|
||||||
|
return content.getString("content");
|
||||||
}
|
}
|
||||||
|
|
||||||
public String textToSpeech(String content) {
|
public String textToSpeech(String content, String language) {
|
||||||
try{
|
try{
|
||||||
Credential cred = new Credential(secretId, secretKey);
|
Credential cred = new Credential(secretId, secretKey);
|
||||||
HttpProfile httpProfile = new HttpProfile();
|
HttpProfile httpProfile = new HttpProfile();
|
||||||
@@ -80,6 +81,9 @@ public class AssistantService {
|
|||||||
req.setText(content);
|
req.setText(content);
|
||||||
req.setSessionId(SnowflakeUtil.getNext());
|
req.setSessionId(SnowflakeUtil.getNext());
|
||||||
req.setVoiceType(101006L);
|
req.setVoiceType(101006L);
|
||||||
|
if (language.equals("English")) {
|
||||||
|
req.setPrimaryLanguage(2L);
|
||||||
|
}
|
||||||
TextToVoiceResponse resp = client.TextToVoice(req);
|
TextToVoiceResponse resp = client.TextToVoice(req);
|
||||||
return resp.getAudio();
|
return resp.getAudio();
|
||||||
} catch (TencentCloudSDKException e) {
|
} catch (TencentCloudSDKException e) {
|
||||||
@@ -159,7 +163,7 @@ public class AssistantService {
|
|||||||
content = getAiResponse(query, language);
|
content = getAiResponse(query, language);
|
||||||
}
|
}
|
||||||
Map<String, Object> map = new HashMap<>();
|
Map<String, Object> map = new HashMap<>();
|
||||||
map.put("content", textToSpeech(content));
|
map.put("content", textToSpeech(content, language));
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ public class NavigateService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, Object> scanTicket(BufferedImage image) {
|
public Map<String, Object> scanTicket(BufferedImage image) {
|
||||||
String base64Img = ImgUtil.toBase64(image, "jpg");
|
String base64Img = ImgUtil.toBase64(image, "png");
|
||||||
SmartStructuralOCRV2Response resp;
|
SmartStructuralOCRV2Response resp;
|
||||||
try {
|
try {
|
||||||
Credential cred = new Credential(secretId, secretKey);
|
Credential cred = new Credential(secretId, secretKey);
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ server.port=8432
|
|||||||
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
|
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
|
||||||
spring.datasource.username=root
|
spring.datasource.username=root
|
||||||
spring.datasource.password=Shuodedaoli114514
|
spring.datasource.password=Shuodedaoli114514
|
||||||
spring.datasource.url=jdbc:mysql://mysql:4514/tutorial?useUnicode=true&characterEncoding=utf8&useSSL=false&ServerTimezone=Asia/Shanghai
|
spring.datasource.url=jdbc:mysql://mysql:3306/tutorial?useUnicode=true&characterEncoding=utf8&useSSL=false&ServerTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
|
||||||
|
|
||||||
spring.cloud.nacos.discovery.server-addr=nacos:8848
|
spring.cloud.nacos.discovery.server-addr=nacos:8848
|
||||||
spring.cloud.nacos.discovery.enabled=true
|
spring.cloud.nacos.discovery.enabled=true
|
||||||
@@ -10,5 +10,5 @@ dubbo.application.qos-enable=false
|
|||||||
|
|
||||||
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
|
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
|
||||||
spring.datasource.username=root
|
spring.datasource.username=root
|
||||||
spring.datasource.password=12345abcde
|
spring.datasource.password=Shuodedaoli114514
|
||||||
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/tutorial?useUnicode=true&characterEncoding=utf8&useSSL=false&ServerTimezone=Asia/Shanghai
|
spring.datasource.url=jdbc:mysql://154.40.44.199:4514/tutorial?useUnicode=true&characterEncoding=utf8&useSSL=false&ServerTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
|
||||||
|
|||||||
7
pom.xml
7
pom.xml
@@ -13,7 +13,7 @@
|
|||||||
<module>user-8072</module>
|
<module>user-8072</module>
|
||||||
<module>commons</module>
|
<module>commons</module>
|
||||||
<module>community-8073</module>
|
<module>community-8073</module>
|
||||||
|
<module>navigate-8432</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
@@ -178,6 +178,11 @@
|
|||||||
<artifactId>sa-token-spring-boot3-starter</artifactId>
|
<artifactId>sa-token-spring-boot3-starter</artifactId>
|
||||||
<version>${satoken-version}</version>
|
<version>${satoken-version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.dev33</groupId>
|
||||||
|
<artifactId>sa-token-redis-jackson</artifactId>
|
||||||
|
<version>${satoken-version}</version>
|
||||||
|
</dependency>
|
||||||
<!-- https://mvnrepository.com/artifact/org.apache.dubbo/dubbo-registry-nacos -->
|
<!-- https://mvnrepository.com/artifact/org.apache.dubbo/dubbo-registry-nacos -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.dubbo</groupId>
|
<groupId>org.apache.dubbo</groupId>
|
||||||
|
|||||||
@@ -65,16 +65,6 @@
|
|||||||
<groupId>org.apache.commons</groupId>
|
<groupId>org.apache.commons</groupId>
|
||||||
<artifactId>commons-pool2</artifactId>
|
<artifactId>commons-pool2</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- dubbo -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.dubbo</groupId>
|
|
||||||
<artifactId>dubbo-spring-boot-starter</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<!-- https://mvnrepository.com/artifact/org.apache.dubbo/dubbo-registry-nacos -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.dubbo</groupId>
|
|
||||||
<artifactId>dubbo-registry-nacos</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.cloud</groupId>
|
<groupId>org.springframework.cloud</groupId>
|
||||||
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
|
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
|
||||||
|
|||||||
@@ -14,14 +14,29 @@ public class RabbitMqConfig {
|
|||||||
return new Queue("queue1",true);
|
return new Queue("queue1",true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Queue queue2() {
|
||||||
|
return new Queue("queue2",true);
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public FanoutExchange exchange1() {
|
public FanoutExchange exchange1() {
|
||||||
return new FanoutExchange("exchange1",true, false);
|
return new FanoutExchange("exchange1",true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public FanoutExchange exchange2() {
|
||||||
|
return new FanoutExchange("exchange2",true, false);
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public Binding binding1() {
|
public Binding binding1() {
|
||||||
return BindingBuilder.bind(queue1()).to(exchange1());
|
return BindingBuilder.bind(queue1()).to(exchange1());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Binding binding2() {
|
||||||
|
return BindingBuilder.bind(queue2()).to(exchange2());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import java.text.ParseException;
|
|||||||
|
|
||||||
@SaCheckLogin
|
@SaCheckLogin
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/message")
|
@RequestMapping("/message")
|
||||||
public class MessageController {
|
public class MessageController {
|
||||||
@Autowired
|
@Autowired
|
||||||
private MessageService messageService;
|
private MessageService messageService;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import org.springframework.web.bind.annotation.*;
|
|||||||
|
|
||||||
@SaCheckLogin
|
@SaCheckLogin
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/relation")
|
@RequestMapping("/relation")
|
||||||
public class RelationController {
|
public class RelationController {
|
||||||
@Autowired
|
@Autowired
|
||||||
private RelationService relationService;
|
private RelationService relationService;
|
||||||
|
|||||||
@@ -2,21 +2,19 @@ package com.ivmiku.tutorial.controller;
|
|||||||
|
|
||||||
import cn.binarywang.wx.miniapp.api.WxMaService;
|
import cn.binarywang.wx.miniapp.api.WxMaService;
|
||||||
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
|
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
|
||||||
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
|
|
||||||
import cn.binarywang.wx.miniapp.util.WxMaConfigHolder;
|
import cn.binarywang.wx.miniapp.util.WxMaConfigHolder;
|
||||||
import cn.dev33.satoken.stp.StpUtil;
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSON;
|
||||||
import com.ivmiku.tutorial.entity.User;
|
import com.ivmiku.tutorial.entity.User;
|
||||||
|
import com.ivmiku.tutorial.entity.UserDTO;
|
||||||
import com.ivmiku.tutorial.mapper.UserMapper;
|
import com.ivmiku.tutorial.mapper.UserMapper;
|
||||||
import com.ivmiku.tutorial.response.Result;
|
import com.ivmiku.tutorial.response.Result;
|
||||||
|
import com.ivmiku.tutorial.service.UserService;
|
||||||
import com.ivmiku.tutorial.utils.RedisUtil;
|
import com.ivmiku.tutorial.utils.RedisUtil;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import me.chanjar.weixin.common.error.WxErrorException;
|
import me.chanjar.weixin.common.error.WxErrorException;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
@@ -32,17 +30,16 @@ public class UserController {
|
|||||||
@Resource
|
@Resource
|
||||||
private RedisUtil redisUtil;
|
private RedisUtil redisUtil;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private UserService userService;
|
||||||
|
|
||||||
@GetMapping("/login")
|
@GetMapping("/login")
|
||||||
public Object login(@RequestParam(name = "code") String code,
|
public Object login(@RequestParam(name = "code") String code,
|
||||||
@RequestParam(name = "rawdata") String rawData,
|
@RequestParam(name = "rawdata") String rawData,
|
||||||
@RequestParam(name = "signature") String signature,
|
@RequestParam(name = "signature") String signature) {
|
||||||
@RequestParam(name = "encryptedData") String encryptedData,
|
|
||||||
@RequestParam(name = "iv") String iv) {
|
|
||||||
WxMaJscode2SessionResult session;
|
WxMaJscode2SessionResult session;
|
||||||
WxMaUserInfo userInfo;
|
|
||||||
try {
|
try {
|
||||||
session = wxMaService.getUserService().getSessionInfo(code);
|
session = wxMaService.getUserService().getSessionInfo(code);
|
||||||
userInfo = wxMaService.getUserService().getUserInfo(session.getSessionKey(), encryptedData, iv);
|
|
||||||
} catch (WxErrorException e) {
|
} catch (WxErrorException e) {
|
||||||
return JSON.toJSON(Result.error(e.getMessage()));
|
return JSON.toJSON(Result.error(e.getMessage()));
|
||||||
}
|
}
|
||||||
@@ -77,4 +74,11 @@ public class UserController {
|
|||||||
}
|
}
|
||||||
return Result.ok();
|
return Result.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/edit")
|
||||||
|
public Object editInfo(@RequestBody UserDTO userDTO) {
|
||||||
|
String loginId = (String) StpUtil.getLoginId();
|
||||||
|
userService.changeUserInfo(userDTO, loginId);
|
||||||
|
return Result.ok();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ package com.ivmiku.tutorial.controller;
|
|||||||
|
|
||||||
import cn.dev33.satoken.stp.StpUtil;
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
import com.ivmiku.tutorial.entity.Message;
|
import com.ivmiku.tutorial.entity.Message;
|
||||||
|
import com.ivmiku.tutorial.response.AtNotifier;
|
||||||
import com.ivmiku.tutorial.service.MessageService;
|
import com.ivmiku.tutorial.service.MessageService;
|
||||||
import com.ivmiku.tutorial.service.RelationService;
|
import com.ivmiku.tutorial.service.RelationService;
|
||||||
import com.ivmiku.tutorial.utils.DateUtil;
|
import com.ivmiku.tutorial.utils.DateUtil;
|
||||||
@@ -84,7 +86,15 @@ public class WebSocketServer implements ApplicationContextAware {
|
|||||||
sessionMap.put(userId, session);
|
sessionMap.put(userId, session);
|
||||||
List<Message> unreadList = messageService.getUnreadMsg(userId);
|
List<Message> unreadList = messageService.getUnreadMsg(userId);
|
||||||
for(Message msg : unreadList) {
|
for(Message msg : unreadList) {
|
||||||
session.getBasicRemote().sendText(JSON.toJSONString(msg));
|
JSONObject object = JSONObject.from(msg);
|
||||||
|
object.put("type", 1);
|
||||||
|
session.getBasicRemote().sendText(object.toJSONString());
|
||||||
|
}
|
||||||
|
List<AtNotifier> atList = messageService.getAtList(userId);
|
||||||
|
for (AtNotifier notifier : atList) {
|
||||||
|
JSONObject object = JSONObject.from(notifier);
|
||||||
|
object.put("type", 2);
|
||||||
|
session.getBasicRemote().sendText(object.toJSONString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,8 +142,25 @@ public class WebSocketServer implements ApplicationContextAware {
|
|||||||
public void sendMsg(String message) throws IOException {
|
public void sendMsg(String message) throws IOException {
|
||||||
Message msg = JSON.parseObject(message, Message.class);
|
Message msg = JSON.parseObject(message, Message.class);
|
||||||
if (sessionMap.containsKey(msg.getToId())) {
|
if (sessionMap.containsKey(msg.getToId())) {
|
||||||
sessionMap.get(msg.getToId()).getBasicRemote().sendText(JSON.toJSONString(msg));
|
JSONObject jsonObject = JSONObject.from(msg);
|
||||||
|
jsonObject.put("type", 1);
|
||||||
|
sessionMap.get(msg.getToId()).getBasicRemote().sendText(jsonObject.toJSONString());
|
||||||
messageService.deleteMessage(msg);
|
messageService.deleteMessage(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RabbitHandler
|
||||||
|
@RabbitListener(bindings = @QueueBinding(
|
||||||
|
value = @Queue(),
|
||||||
|
exchange = @Exchange(value = "exchange2",type = ExchangeTypes.FANOUT)
|
||||||
|
))
|
||||||
|
public void sendAt(String message) throws IOException {
|
||||||
|
AtNotifier notifier = JSON.parseObject(message, AtNotifier.class);
|
||||||
|
if (sessionMap.containsKey(notifier.getToId())) {
|
||||||
|
JSONObject jsonObject = JSONObject.from(notifier);
|
||||||
|
jsonObject.put("type", 2);
|
||||||
|
sessionMap.get(notifier.getToId()).getBasicRemote().sendText(jsonObject.toJSONString());
|
||||||
|
messageService.deleteNotifier(notifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package com.ivmiku.tutorial.entity;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class UserDTO {
|
||||||
|
private String nickname;
|
||||||
|
private String avatarUrl;
|
||||||
|
private String phoneNum;
|
||||||
|
private String birthday;
|
||||||
|
private String gender;
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ import com.ivmiku.tutorial.entity.ChatId;
|
|||||||
import com.ivmiku.tutorial.entity.Message;
|
import com.ivmiku.tutorial.entity.Message;
|
||||||
import com.ivmiku.tutorial.mapper.ChatIdMapper;
|
import com.ivmiku.tutorial.mapper.ChatIdMapper;
|
||||||
import com.ivmiku.tutorial.mapper.MessageMapper;
|
import com.ivmiku.tutorial.mapper.MessageMapper;
|
||||||
|
import com.ivmiku.tutorial.response.AtNotifier;
|
||||||
import com.ivmiku.tutorial.utils.RedisUtil;
|
import com.ivmiku.tutorial.utils.RedisUtil;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.scheduling.annotation.Async;
|
import org.springframework.scheduling.annotation.Async;
|
||||||
@@ -245,4 +246,12 @@ public class MessageService {
|
|||||||
public void deleteMessage(Message message) {
|
public void deleteMessage(Message message) {
|
||||||
redisUtil.deleteFromList(message);
|
redisUtil.deleteFromList(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void deleteNotifier(AtNotifier notifier) {
|
||||||
|
redisUtil.deleteFromList(notifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<AtNotifier> getAtList(String userId) {
|
||||||
|
return redisUtil.listGetN("at:" + userId, 0, -1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package com.ivmiku.tutorial.service;
|
package com.ivmiku.tutorial.service;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.DesensitizedUtil;
|
||||||
|
import cn.hutool.crypto.SecureUtil;
|
||||||
import com.ivmiku.tutorial.entity.User;
|
import com.ivmiku.tutorial.entity.User;
|
||||||
|
import com.ivmiku.tutorial.entity.UserDTO;
|
||||||
import com.ivmiku.tutorial.mapper.UserMapper;
|
import com.ivmiku.tutorial.mapper.UserMapper;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@@ -13,4 +16,30 @@ public class UserService {
|
|||||||
public User selectUserById(String id) {
|
public User selectUserById(String id) {
|
||||||
return userMapper.selectById(id);
|
return userMapper.selectById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void changeUserInfo(UserDTO userDTO, String openid) {
|
||||||
|
String nickname = userDTO.getNickname();
|
||||||
|
String avatarUrl = userDTO.getAvatarUrl();
|
||||||
|
String gender = userDTO.getGender();
|
||||||
|
String phoneNum = userDTO.getPhoneNum();
|
||||||
|
String birthday = userDTO.getBirthday();
|
||||||
|
User user = userMapper.selectById(openid);
|
||||||
|
if (nickname != null) {
|
||||||
|
user.setNickname(nickname);
|
||||||
|
}
|
||||||
|
if (avatarUrl != null) {
|
||||||
|
user.setAvatarUrl(avatarUrl);
|
||||||
|
}
|
||||||
|
if (gender != null) {
|
||||||
|
user.setGender(gender);
|
||||||
|
}
|
||||||
|
if (phoneNum != null) {
|
||||||
|
phoneNum = DesensitizedUtil.mobilePhone(phoneNum);
|
||||||
|
user.setPhoneNum(phoneNum);
|
||||||
|
}
|
||||||
|
if (birthday != null) {
|
||||||
|
user.setBirthday(birthday);
|
||||||
|
}
|
||||||
|
userMapper.updateById(user);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.ivmiku.tutorial.utils;
|
|||||||
|
|
||||||
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSON;
|
||||||
import com.ivmiku.tutorial.entity.Message;
|
import com.ivmiku.tutorial.entity.Message;
|
||||||
|
import com.ivmiku.tutorial.response.AtNotifier;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@@ -127,4 +128,24 @@ public class RedisUtil {
|
|||||||
String id = message.getToId();
|
String id = message.getToId();
|
||||||
redisTemplate.opsForList().remove("unread:" + id, 0, message);
|
redisTemplate.opsForList().remove("unread:" + id, 0, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void listAddN(String key, Object value) {
|
||||||
|
redisTemplate.opsForList().leftPush(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<AtNotifier> listGetN(String key, int s, int e) {
|
||||||
|
List<Object> list = redisTemplate.opsForList().range(key, s, e);
|
||||||
|
List<AtNotifier> result = new ArrayList<>();
|
||||||
|
if (list != null) {
|
||||||
|
for (Object json : list) {
|
||||||
|
result.add(JSON.parseObject(JSON.toJSONString(json), AtNotifier.class));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteFromList(AtNotifier message) {
|
||||||
|
String id = message.getToId();
|
||||||
|
redisTemplate.opsForList().remove("unread:" + id, 0, message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ wx.miniapp.configs[0].secret=989f155fcc3aee616568473faf1b1d3b
|
|||||||
spring.data.redis.host=redis
|
spring.data.redis.host=redis
|
||||||
spring.data.redis.port=6379
|
spring.data.redis.port=6379
|
||||||
spring.data.redis.database=0
|
spring.data.redis.database=0
|
||||||
|
spring.data.redis.password=Shuodedaoli114514
|
||||||
|
|
||||||
spring.application.name=user
|
spring.application.name=user
|
||||||
|
|
||||||
@@ -11,10 +12,10 @@ server.port=8072
|
|||||||
|
|
||||||
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
|
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
|
||||||
spring.datasource.username=root
|
spring.datasource.username=root
|
||||||
spring.datasource.password=123456
|
spring.datasource.password=Shuodedaoli114514
|
||||||
spring.datasource.url=jdbc:mysql://mysql:3306/tutorial?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
|
spring.datasource.url=jdbc:mysql://mysql:3306/tutorial?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
|
||||||
|
|
||||||
spring.cloud.nacos.discovery.server-addr=nacos:8848
|
spring.cloud.nacos.discovery.server-addr=nacos:8848
|
||||||
spring.cloud.nacos.discovery.enabled=true
|
spring.cloud.nacos.discovery.enabled=true
|
||||||
|
|
||||||
|
spring.rabbitmq.host=rabbitmq
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
spring.profiles.active=dev
|
spring.profiles.active=dep
|
||||||
Reference in New Issue
Block a user