From 0244267ab74904ecc7aefabcfe53eaeb5e53ba6d Mon Sep 17 00:00:00 2001 From: LingandRX Date: Tue, 13 May 2025 22:05:45 +0800 Subject: [PATCH] =?UTF-8?q?feat(question):=20=E6=B7=BB=E5=8A=A0=E9=97=AE?= =?UTF-8?q?=E9=A2=98=E7=9B=B8=E5=85=B3=E5=8A=9F=E8=83=BD-=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E9=A2=98=E5=8D=95=E7=9B=B8=E5=85=B3=E5=AE=9E=E4=BD=93?= =?UTF-8?q?=E5=92=8C=E6=8E=A5=E5=8F=A3=20-=20=E5=AE=9E=E7=8E=B0=E9=97=AE?= =?UTF-8?q?=E9=A2=98=E5=88=97=E8=A1=A8=E8=8E=B7=E5=8F=96=E3=80=81=E9=97=AE?= =?UTF-8?q?=E9=A2=98=E5=88=9B=E5=BB=BA=E3=80=81=E6=9B=B4=E6=96=B0=E5=92=8C?= =?UTF-8?q?=E5=88=A0=E9=99=A4=E5=8A=9F=E8=83=BD=20-=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E9=97=AE=E9=A2=98=E5=88=97=E8=A1=A8=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=E5=92=8C=E5=8D=95=E4=B8=AA=E9=97=AE=E9=A2=98=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=E5=8A=9F=E8=83=BD=20-=20=E5=AE=9E=E7=8E=B0=E9=97=AE?= =?UTF-8?q?=E9=A2=98=E6=90=9C=E7=B4=A2=E5=8A=9F=E8=83=BD=20-=20=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E6=B6=88=E6=81=AF=E6=9C=8D=E5=8A=A1=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=20-=20=E9=87=8D=E6=9E=84=E9=83=A8=E5=88=86=E7=8E=B0=E6=9C=89?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E7=9A=84=E4=BB=A3=E7=A0=81=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/UserController.java | 7 - .../copykamanotes/mapper/MessageMapper.java | 75 +++++++++ .../mapper/QuestionListMapper.java | 49 ++++++ .../copykamanotes/mapper/UserMapper.java | 124 ++++++++++++-- .../model/entity/QuestionList.java | 33 ++++ .../service/CollectionService.java | 1 - .../service/QuestionListItemService.java | 3 +- .../service/QuestionService.java | 3 +- .../copykamanotes/service/SearchService.java | 2 +- .../copykamanotes/service/UserService.java | 2 - .../service/impl/CategoryServiceImpl.java | 10 +- .../impl/CollectionNoteServiceImpl.java | 5 +- .../service/impl/CollectionServiceImpl.java | 17 +- .../service/impl/EmailServiceImpl.java | 13 +- .../service/impl/MessageServiceImpl.java | 119 +++++++++++++- .../service/impl/NoteServiceImpl.java | 28 +--- .../impl/QuestionListItemServiceImpl.java | 136 ++++++++++++++++ .../service/impl/QuestionListServiceImpl.java | 80 +++++++++ .../service/impl/QuestionServiceImpl.java | 154 ++++++++++++++++-- .../service/impl/RedisServiceImpl.java | 6 +- .../service/impl/SearchServiceImpl.java | 102 ++++++++++++ .../service/impl/UploadServiceImpl.java | 5 +- .../service/impl/UserServiceImpl.java | 58 +------ 23 files changed, 891 insertions(+), 141 deletions(-) create mode 100644 src/main/java/com/example/copykamanotes/mapper/QuestionListMapper.java create mode 100644 src/main/java/com/example/copykamanotes/service/impl/QuestionListItemServiceImpl.java create mode 100644 src/main/java/com/example/copykamanotes/service/impl/QuestionListServiceImpl.java create mode 100644 src/main/java/com/example/copykamanotes/service/impl/SearchServiceImpl.java diff --git a/src/main/java/com/example/copykamanotes/controller/UserController.java b/src/main/java/com/example/copykamanotes/controller/UserController.java index 19bcd94..9b184e4 100644 --- a/src/main/java/com/example/copykamanotes/controller/UserController.java +++ b/src/main/java/com/example/copykamanotes/controller/UserController.java @@ -71,11 +71,4 @@ public class UserController { ) { return userService.getUserList(userQueryParam); } - - @PostMapping("/users/resetPassword") - public ApiResponse updateUserPassword( - @RequestBody UserRestPasswordRequest userRestPasswordRequest - ) { - return userService.updateUserPassword(userRestPasswordRequest.getOldPassword(), userRestPasswordRequest.getNewPassword()); - } } diff --git a/src/main/java/com/example/copykamanotes/mapper/MessageMapper.java b/src/main/java/com/example/copykamanotes/mapper/MessageMapper.java index 6984e6c..d58beac 100644 --- a/src/main/java/com/example/copykamanotes/mapper/MessageMapper.java +++ b/src/main/java/com/example/copykamanotes/mapper/MessageMapper.java @@ -1,9 +1,84 @@ package com.example.copykamanotes.mapper; +import com.example.copykamanotes.model.dto.message.MessageQueryParams; import com.example.copykamanotes.model.entity.Message; +import com.example.copykamanotes.model.vo.message.UnreadCountByType; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import java.util.List; + +/** + * 消息Mapper接口 + */ @Mapper public interface MessageMapper { + /** + * 插入消息 + * + * @param message 消息实体 + * @return 影响行数 + */ int insert(Message message); + + /** + * 根据参数查询消息列表 + * + * @param userId 用户ID + * @param params 查询参数 + * @param offset 偏移量 + * @return 消息列表 + */ + List selectByParams(@Param("userId") Long userId, @Param("params") MessageQueryParams params, @Param("offset") int offset); + + /** + * 统计符合条件的消息数量 + * + * @param userId 用户ID + * @param params 查询参数 + * @return 消息数量 + */ + int countByParams(@Param("userId") Long userId, @Param("params") MessageQueryParams params); + + /** + * 标记消息为已读 + * + * @param messageId 消息ID + * @param userId 用户ID + * @return 影响行数 + */ + int markAsRead(@Param("messageId") Integer messageId, @Param("userId") Long userId); + + /** + * 标记所有消息为已读 + * + * @param userId 用户ID + * @return 影响行数 + */ + int markAllAsRead(@Param("userId") Long userId); + + /** + * 删除消息 + * + * @param messageId 消息ID + * @param userId 用户ID + * @return 影响行数 + */ + int deleteMessage(@Param("messageId") Integer messageId, @Param("userId") Long userId); + + /** + * 统计未读消息数量 + * + * @param userId 用户ID + * @return 未读消息数量 + */ + int countUnread(@Param("userId") Long userId); + + /** + * 按类型统计未读消息数量 + * + * @param userId 用户ID + * @return 各类型未读消息数量 + */ + List countUnreadByType(@Param("userId") Long userId); } diff --git a/src/main/java/com/example/copykamanotes/mapper/QuestionListMapper.java b/src/main/java/com/example/copykamanotes/mapper/QuestionListMapper.java new file mode 100644 index 0000000..eba3bf3 --- /dev/null +++ b/src/main/java/com/example/copykamanotes/mapper/QuestionListMapper.java @@ -0,0 +1,49 @@ +package com.example.copykamanotes.mapper; + +import com.example.copykamanotes.model.entity.QuestionList; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +@Mapper +public interface QuestionListMapper { + /** + * 插入一个题单 + * + * @param questionList 要插入的题单对象 + * @return 插入操作影响的行数 + */ + int insert(QuestionList questionList); + + /** + * 根据题单ID查找题单 + * + * @param questionListId 题单的唯一标识符 + * @return 返回找到的题单对象,如果没有找到则返回 null + */ + QuestionList findById(@Param("questionListId") Integer questionListId); + + /** + * 获取所有题单 + * + * @return 返回所有题单的列表 + */ + List findAll(); + + /** + * 更新一个题单的信息 + * + * @param questionList 要更新的题单对象,包含需要更新的字段 + * @return 更新操作影响的行数 + */ + int update(QuestionList questionList); + + /** + * 根据题单ID删除题单 + * + * @param questionListId 题单的唯一标识符 + * @return 删除操作影响的行数 + */ + int deleteById(@Param("questionListId") Integer questionListId); +} diff --git a/src/main/java/com/example/copykamanotes/mapper/UserMapper.java b/src/main/java/com/example/copykamanotes/mapper/UserMapper.java index 0e83250..ce49c0f 100644 --- a/src/main/java/com/example/copykamanotes/mapper/UserMapper.java +++ b/src/main/java/com/example/copykamanotes/mapper/UserMapper.java @@ -10,27 +10,127 @@ import java.util.List; @Mapper public interface UserMapper { /** - * 新增用户 + * 插入新用户 * - * @param user 用户信息 + * @param user 待插入的用户对象,包含用户的所有信息 */ int insert(User user); - User findByAccount(@Param("account") String account); - - User findByEmail(@Param("email") String email); - - int updateLastLoginAt(@Param("userId") Long userId); - + /** + * 根据ID查找用户 + * + * @param userId 用户ID,用于查询用户信息 + * @return 返回用户对象,如果未找到则返回null + */ User findById(@Param("userId") Long userId); + /** + * 根据 ID 数组批量查找用户 + * + * @param userIds 用户ID列表,用于批量查询用户信息 + * @return 返回用户列表,如果未找到任何用户则返回空列表 + */ + List findByIdBatch(@Param("userIds") List userIds); + + /** + * 根据账号查找用户 + * + * @param account 用户账号,用于查询用户信息 + * @return 返回用户对象,如果未找到则返回null + */ + User findByAccount(@Param("account") String account); + + /** + * 根据 OpenId 查找用户 + * + * @param openId 用户的 OpenId,用于查询用户信息 + * @return 返回用户对象,如果未找到则返回 null + */ + User findByOpenId(@Param("openId") String openId); + + /** + * 根据 UnionId 查找用户 + * + * @param unionId 用户的 UnionId,用于查询用户信息 + * @return 返回用户对象,如果未找到则返回 null + */ + User findByUnionId(@Param("unionId") String unionId); + + /** + * 根据查询参数查找用户列表 + * + * @param queryParams 用户查询参数对象,封装了查询用户时的各种筛选条件 + * @return 符合查询条件的用户列表 + */ + List findByQueryParam(@Param("queryParams") UserQueryParam queryParams, + @Param("limit") Integer limit, + @Param("offset") Integer offset); + + /** + * 根据查询参数统计用户数量 + * + * @param queryParams 用户查询参数对象,封装了查询条件 + * @return 满足查询条件的用户数量 + */ + int countByQueryParam(@Param("queryParams") UserQueryParam queryParams); + + /** + * 更新用户信息 + * + * @param user 待更新的用户对象,包含用户的所有信息 + */ int update(User user); - int updatePassword(@Param("userId") Long userId, @Param("password") String password); + /** + * 更新用户在线时间 + * + * @param userId 用户ID,用于标识需要更新在线时间的用户 + */ + int updateLastLoginAt(@Param("userId") Long userId); - List findByIds(@Param("userIds") List userIds); + /** + * 绑定手机号 + * @param userId 用户ID + * @param phone 手机号码 + * @return 绑定结果 + */ + int bindPhone(@Param("userId") Long userId, @Param("phone") String phone); - int countByQueryParam(@Param("queryParams") UserQueryParam userQueryParam); + /** + * 获取今日登录人数 + * @return 今日登录人数 + */ + int getTodayLoginCount(); - List findByQueryParam(@Param("queryParams") UserQueryParam userQueryParam, @Param("limit") int pageSize, @Param("offset") int offset); + /** + * 今日注册人数 + * @return 今日注册人数 + */ + int getTodayRegisterCount(); + + /** + * 总注册人数 + * @return 总注册人数 + */ + int getTotalRegisterCount(); + + /** + * 根据邮箱查找用户 + * + * @param email 用户邮箱,用于查询用户信息 + * @return 返回用户对象,如果未找到则返回null + */ + User findByEmail(@Param("email") String email); + + /** + * 搜索用户 + * + * @param keyword 关键词 + * @param limit 限制数量 + * @param offset 偏移量 + * @return 用户列表 + */ + List searchUsers(@Param("keyword") String keyword, + @Param("limit") int limit, + @Param("offset") int offset); } diff --git a/src/main/java/com/example/copykamanotes/model/entity/QuestionList.java b/src/main/java/com/example/copykamanotes/model/entity/QuestionList.java index 448d1d2..1eb9108 100644 --- a/src/main/java/com/example/copykamanotes/model/entity/QuestionList.java +++ b/src/main/java/com/example/copykamanotes/model/entity/QuestionList.java @@ -1,4 +1,37 @@ package com.example.copykamanotes.model.entity; +import lombok.Data; +import java.util.Date; + +@Data public class QuestionList { + /* + * 题单ID(主键) + */ + private Integer questionListId; + + /* + * 题单名称 + */ + private String name; + + /** + * 题单类型 + */ + private Integer type; + + /* + * 题单描述 + */ + private String description; + + /* + * 创建时间 + */ + private Date createdAt; + + /* + * 更新时间 + */ + private Date updatedAt; } diff --git a/src/main/java/com/example/copykamanotes/service/CollectionService.java b/src/main/java/com/example/copykamanotes/service/CollectionService.java index 5e364f4..066f0a8 100644 --- a/src/main/java/com/example/copykamanotes/service/CollectionService.java +++ b/src/main/java/com/example/copykamanotes/service/CollectionService.java @@ -5,7 +5,6 @@ import com.example.copykamanotes.model.base.EmptyVO; import com.example.copykamanotes.model.dto.collection.CollectionQueryParams; import com.example.copykamanotes.model.dto.collection.CreateCollectionBody; import com.example.copykamanotes.model.dto.collection.UpdateCollectionBody; -import com.example.copykamanotes.model.entity.Collection; import com.example.copykamanotes.model.vo.collection.CollectionVO; import com.example.copykamanotes.model.vo.collection.CreateCollectionVO; import org.springframework.transaction.annotation.Transactional; diff --git a/src/main/java/com/example/copykamanotes/service/QuestionListItemService.java b/src/main/java/com/example/copykamanotes/service/QuestionListItemService.java index adb59c4..8119a27 100644 --- a/src/main/java/com/example/copykamanotes/service/QuestionListItemService.java +++ b/src/main/java/com/example/copykamanotes/service/QuestionListItemService.java @@ -7,6 +7,7 @@ import com.example.copykamanotes.model.dto.questionListItem.QuestionListItemQuer import com.example.copykamanotes.model.dto.questionListItem.SortQuestionListItemBody; import com.example.copykamanotes.model.vo.questionListItem.CreateQuestionListItemVO; import com.example.copykamanotes.model.vo.questionListItem.QuestionListItemUserVO; +import com.example.copykamanotes.model.vo.questionListItem.QuestionListItemVO; import org.springframework.transaction.annotation.Transactional; import java.util.List; @@ -15,7 +16,7 @@ import java.util.List; public interface QuestionListItemService { ApiResponse> useGetQuestionListItemUserVO(QuestionListItemQueryParams questionListItemQueryParams); - ApiResponse> getQuestionListItem(Integer questionListId); + ApiResponse> getQuestionListItems(Integer questionListId); ApiResponse createQuestionListItem(CreateQuestionListItemBody createQuestionListItemBody); diff --git a/src/main/java/com/example/copykamanotes/service/QuestionService.java b/src/main/java/com/example/copykamanotes/service/QuestionService.java index 4fcf4b5..6177074 100644 --- a/src/main/java/com/example/copykamanotes/service/QuestionService.java +++ b/src/main/java/com/example/copykamanotes/service/QuestionService.java @@ -9,6 +9,7 @@ import com.example.copykamanotes.model.dto.question.UpdateQuestionBody; import com.example.copykamanotes.model.entity.Question; import com.example.copykamanotes.model.vo.question.CreateQuestionVO; import com.example.copykamanotes.model.vo.question.QuestionNoteVO; +import com.example.copykamanotes.model.vo.question.QuestionUserVO; import com.example.copykamanotes.model.vo.question.QuestionVO; import org.springframework.transaction.annotation.Transactional; @@ -30,7 +31,7 @@ public interface QuestionService { ApiResponse deleteQuestion(Integer questionId); - ApiResponse> userGetQuestions(QuestionQueryParam queryParam); + ApiResponse> userGetQuestions(QuestionQueryParam queryParam); ApiResponse userGetQuestion(Integer questionId); diff --git a/src/main/java/com/example/copykamanotes/service/SearchService.java b/src/main/java/com/example/copykamanotes/service/SearchService.java index 5b359a6..6f02352 100644 --- a/src/main/java/com/example/copykamanotes/service/SearchService.java +++ b/src/main/java/com/example/copykamanotes/service/SearchService.java @@ -11,5 +11,5 @@ public interface SearchService { ApiResponse> searchUsers(String keyword, int page, int pageSize); - ApiResponse> searchNotesByTag(String keyword, int page, int pageSize); + ApiResponse> searchNotesByTag(String keyword, String tag, int page, int pageSize); } diff --git a/src/main/java/com/example/copykamanotes/service/UserService.java b/src/main/java/com/example/copykamanotes/service/UserService.java index 0e72e5b..e59fcd5 100644 --- a/src/main/java/com/example/copykamanotes/service/UserService.java +++ b/src/main/java/com/example/copykamanotes/service/UserService.java @@ -66,8 +66,6 @@ public interface UserService { */ Map getUserMapByIds(List authorIds); - ApiResponse updateUserPassword(String oldPassword, String newPassword); - /** * 获取用户列表 * @param userQueryParam 查询参数 diff --git a/src/main/java/com/example/copykamanotes/service/impl/CategoryServiceImpl.java b/src/main/java/com/example/copykamanotes/service/impl/CategoryServiceImpl.java index f377ff1..87cbebd 100644 --- a/src/main/java/com/example/copykamanotes/service/impl/CategoryServiceImpl.java +++ b/src/main/java/com/example/copykamanotes/service/impl/CategoryServiceImpl.java @@ -11,6 +11,7 @@ import com.example.copykamanotes.model.vo.category.CategoryVO; import com.example.copykamanotes.model.vo.category.CreateCategoryVO; import com.example.copykamanotes.service.CategoryService; import com.example.copykamanotes.utils.ApiResponseUtils; +import lombok.RequiredArgsConstructor; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -21,14 +22,11 @@ import java.util.List; import java.util.Map; @Service +@RequiredArgsConstructor public class CategoryServiceImpl implements CategoryService { - @Autowired - private CategoryMapper categoryMapper; - - - @Autowired - private QuestionMapper questionMapper; + private final CategoryMapper categoryMapper; + private final QuestionMapper questionMapper; @Override public ApiResponse updateCategory(Integer id, UpdateCategoryBody updateCategoryBody) { diff --git a/src/main/java/com/example/copykamanotes/service/impl/CollectionNoteServiceImpl.java b/src/main/java/com/example/copykamanotes/service/impl/CollectionNoteServiceImpl.java index a8570d5..5d69914 100644 --- a/src/main/java/com/example/copykamanotes/service/impl/CollectionNoteServiceImpl.java +++ b/src/main/java/com/example/copykamanotes/service/impl/CollectionNoteServiceImpl.java @@ -2,6 +2,7 @@ package com.example.copykamanotes.service.impl; import com.example.copykamanotes.mapper.CollectionNoteMapper; import com.example.copykamanotes.service.CollectionNoteService; +import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -10,10 +11,10 @@ import java.util.List; import java.util.Set; @Service +@RequiredArgsConstructor public class CollectionNoteServiceImpl implements CollectionNoteService { - @Autowired - private CollectionNoteMapper collectionNoteMapper; + private final CollectionNoteMapper collectionNoteMapper; @Override public Set findUserCollectionNoteIds(Long userId, List noteIds) { diff --git a/src/main/java/com/example/copykamanotes/service/impl/CollectionServiceImpl.java b/src/main/java/com/example/copykamanotes/service/impl/CollectionServiceImpl.java index 20f7b89..4db98ea 100644 --- a/src/main/java/com/example/copykamanotes/service/impl/CollectionServiceImpl.java +++ b/src/main/java/com/example/copykamanotes/service/impl/CollectionServiceImpl.java @@ -16,6 +16,7 @@ import com.example.copykamanotes.model.vo.collection.CreateCollectionVO; import com.example.copykamanotes.scope.RequestScopeData; import com.example.copykamanotes.service.CollectionService; import com.example.copykamanotes.utils.ApiResponseUtils; +import lombok.RequiredArgsConstructor; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -26,19 +27,13 @@ import java.util.List; import java.util.Set; @Service +@RequiredArgsConstructor public class CollectionServiceImpl implements CollectionService { - @Autowired - private RequestScopeData requestScopeData; - - @Autowired - private CollectionMapper collectionMapper; - - @Autowired - private CollectionNoteMapper collectionNoteMapper; - - @Autowired - private NoteMapper noteMapper; + private final RequestScopeData requestScopeData; + private final CollectionMapper collectionMapper; + private final CollectionNoteMapper collectionNoteMapper; + private final NoteMapper noteMapper; @Override public ApiResponse> getCollection(CollectionQueryParams queryParams) { diff --git a/src/main/java/com/example/copykamanotes/service/impl/EmailServiceImpl.java b/src/main/java/com/example/copykamanotes/service/impl/EmailServiceImpl.java index 3d36f65..02b6420 100644 --- a/src/main/java/com/example/copykamanotes/service/impl/EmailServiceImpl.java +++ b/src/main/java/com/example/copykamanotes/service/impl/EmailServiceImpl.java @@ -3,6 +3,7 @@ package com.example.copykamanotes.service.impl; import com.example.copykamanotes.mapper.EmailVerifyCodeMapper; import com.example.copykamanotes.model.entity.EmailVerifyCode; import com.example.copykamanotes.service.EmailService; +import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -17,16 +18,12 @@ import java.util.concurrent.TimeUnit; @Slf4j @Service +@RequiredArgsConstructor public class EmailServiceImpl implements EmailService { - @Autowired - private JavaMailSender javaMailSender; - - @Autowired - private EmailVerifyCodeMapper emailVerifyCodeMapper; - - @Autowired - private RedisTemplate redisTemplate; + private final JavaMailSender javaMailSender; + private final EmailVerifyCodeMapper emailVerifyCodeMapper; + private final RedisTemplate redisTemplate; @Value("${spring.mail.username}") private String fromEmail; diff --git a/src/main/java/com/example/copykamanotes/service/impl/MessageServiceImpl.java b/src/main/java/com/example/copykamanotes/service/impl/MessageServiceImpl.java index 39d331f..f6d00ec 100644 --- a/src/main/java/com/example/copykamanotes/service/impl/MessageServiceImpl.java +++ b/src/main/java/com/example/copykamanotes/service/impl/MessageServiceImpl.java @@ -1,50 +1,155 @@ package com.example.copykamanotes.service.impl; +import com.example.copykamanotes.mapper.MessageMapper; +import com.example.copykamanotes.mapper.UserMapper; import com.example.copykamanotes.model.base.ApiResponse; import com.example.copykamanotes.model.base.EmptyVO; import com.example.copykamanotes.model.base.PageVO; import com.example.copykamanotes.model.dto.message.MessageQueryParams; +import com.example.copykamanotes.model.entity.Message; +import com.example.copykamanotes.model.entity.User; import com.example.copykamanotes.model.vo.message.MessageVO; import com.example.copykamanotes.model.vo.message.UnreadCountByType; import com.example.copykamanotes.service.MessageService; +import com.example.copykamanotes.utils.SecurityUtils; +import lombok.RequiredArgsConstructor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; +import java.time.LocalDateTime; import java.util.List; +import java.util.concurrent.TimeUnit; @Service +@RequiredArgsConstructor public class MessageServiceImpl implements MessageService { + + private final MessageMapper messageMapper; + private final UserMapper userMapper; + private final RedisTemplate redisTemplate; + private static final Logger log = LoggerFactory.getLogger(MessageServiceImpl.class); + + private static final String UNREAD_COUNT_KEY = "message:unread:count"; + private static final String UNREAD_COUNT_BY_TYPE_KEY = "message:unread:type:"; + private static final String MESSAGE_CACHE_KEY = "message:detail:"; + @Override public ApiResponse createMessage(Long receiverId, Long senderId, String type, Integer targetId, String content) { - return null; + + log.info("创建消息: {}", receiverId); + + try { + Message message = new Message(); + message.setReceiverId(receiverId); + message.setType(type); + message.setTargetId(targetId); + message.setContent(content); + message.setCreatedAt(LocalDateTime.now()); + message.setUpdatedAt(LocalDateTime.now()); + + int rows = messageMapper.insert(message); + log.info("创建消息成功: {}", rows); + + clearMessageCache(receiverId); + + return ApiResponse.success(message.getMessageId()); + } catch (Exception e) { + return ApiResponse.error(500, "创建消息失败"); + } } @Override public ApiResponse markAsRead(Integer messageId) { - return null; + Long currentUserId = SecurityUtils.getCurrentUserId(); + + messageMapper.markAsRead(messageId, currentUserId); + clearMessageCache(currentUserId); + return ApiResponse.success(); } @Override public ApiResponse markAllAsRead() { - return null; + Long currentUserId = SecurityUtils.getCurrentUserId(); + messageMapper.markAllAsRead(currentUserId); + + clearMessageCache(currentUserId); + + return ApiResponse.success(); } @Override public ApiResponse deleteMessage(Integer messageId) { - return null; + Long currentUserId = SecurityUtils.getCurrentUserId(); + messageMapper.deleteMessage(messageId, currentUserId); + return ApiResponse.success(); } @Override public ApiResponse getUnreadCount() { - return null; + Long currentUserId = SecurityUtils.getCurrentUserId(); + String cacheKey = UNREAD_COUNT_KEY + currentUserId; + Integer count = (Integer) redisTemplate.opsForValue().get(cacheKey); + if (count == null) { + count = messageMapper.countUnread(currentUserId); + redisTemplate.opsForValue().set(cacheKey, count, 5, TimeUnit.MINUTES); + } + return ApiResponse.success(count); } @Override public ApiResponse> getUnreadCountByType() { - return null; + Long currentUserId = SecurityUtils.getCurrentUserId(); + String cacheKey = UNREAD_COUNT_BY_TYPE_KEY + currentUserId; + + @SuppressWarnings("unchecked") + List result = (List) redisTemplate.opsForValue().get(cacheKey); + if (result == null) { + result = messageMapper.countUnreadByType(currentUserId); + redisTemplate.opsForValue().set(cacheKey, result, 5, TimeUnit.MINUTES); + } + + return ApiResponse.success(result); } @Override public ApiResponse> getMessages(MessageQueryParams params) { - return null; + + Long currentUserId = SecurityUtils.getCurrentUserId(); + + int total = messageMapper.countByParams(currentUserId, params); + + int offset = (params.getPage() - 1) * params.getPageSize(); + + List messages = messageMapper.selectByParams(currentUserId, params, offset); + + List messageVOS = messages.stream().map(message -> { + MessageVO messageVO = new MessageVO(); + messageVO.setMessageId(message.getMessageId()); + messageVO.setType(message.getType()); + messageVO.setTargetId(message.getTargetId()); + messageVO.setContent(message.getContent()); + messageVO.setIsRead(message.getIsRead()); + messageVO.setCreatedAt(message.getCreatedAt()); + + User sender = userMapper.findById(message.getSenderId()); + if (sender != null) { + MessageVO.SimpleUserVO senderVO = new MessageVO.SimpleUserVO(); + senderVO.setUserId(sender.getUserId()); + senderVO.setUsername(sender.getUsername()); + senderVO.setAvatarUrl(sender.getAvatarUrl()); + messageVO.setSender(senderVO); + } + return messageVO; + }).toList(); + + PageVO pageVO = PageVO.of(params.getPage(), params.getPageSize(), total, messageVOS); + return ApiResponse.success(pageVO); + } + + private void clearMessageCache(Long userId) { + redisTemplate.delete(UNREAD_COUNT_KEY + userId); + redisTemplate.delete(UNREAD_COUNT_BY_TYPE_KEY + userId); } } diff --git a/src/main/java/com/example/copykamanotes/service/impl/NoteServiceImpl.java b/src/main/java/com/example/copykamanotes/service/impl/NoteServiceImpl.java index ad7ad74..070fb71 100644 --- a/src/main/java/com/example/copykamanotes/service/impl/NoteServiceImpl.java +++ b/src/main/java/com/example/copykamanotes/service/impl/NoteServiceImpl.java @@ -17,34 +17,24 @@ import com.example.copykamanotes.service.*; import com.example.copykamanotes.utils.ApiResponseUtils; import com.example.copykamanotes.utils.MarkdownUtils; import com.example.copykamanotes.utils.PaginationUtils; +import lombok.RequiredArgsConstructor; import org.springframework.beans.BeanUtils; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.*; import java.util.stream.Collectors; @Service +@RequiredArgsConstructor public class NoteServiceImpl implements NoteService { - @Autowired - private NoteMapper noteMapper; - - @Autowired - private UserService userService; - - @Autowired - private QuestionService questionService; - - @Autowired - private NoteLikeService noteLikeService; - - @Autowired - private RequestScopeData requestScopeData; - @Autowired - private CategoryService categoryService; - @Autowired - private QuestionMapper questionMapper; + private final NoteMapper noteMapper; + private final UserService userService; + private final QuestionService questionService; + private final NoteLikeService noteLikeService; + private final RequestScopeData requestScopeData; + private final CategoryService categoryService; + private final QuestionMapper questionMapper; @Override public ApiResponse> getNotes(NoteQueryParams noteQueryParams) { diff --git a/src/main/java/com/example/copykamanotes/service/impl/QuestionListItemServiceImpl.java b/src/main/java/com/example/copykamanotes/service/impl/QuestionListItemServiceImpl.java new file mode 100644 index 0000000..93fd346 --- /dev/null +++ b/src/main/java/com/example/copykamanotes/service/impl/QuestionListItemServiceImpl.java @@ -0,0 +1,136 @@ +package com.example.copykamanotes.service.impl; + +import com.example.copykamanotes.mapper.NoteMapper; +import com.example.copykamanotes.mapper.QuestionListItemMapper; +import com.example.copykamanotes.mapper.QuestionListMapper; +import com.example.copykamanotes.mapper.UserMapper; +import com.example.copykamanotes.model.base.ApiResponse; +import com.example.copykamanotes.model.base.EmptyVO; +import com.example.copykamanotes.model.base.Pagination; +import com.example.copykamanotes.model.dto.questionListItem.CreateQuestionListItemBody; +import com.example.copykamanotes.model.dto.questionListItem.QuestionListItemQueryParams; +import com.example.copykamanotes.model.dto.questionListItem.SortQuestionListItemBody; +import com.example.copykamanotes.model.entity.QuestionList; +import com.example.copykamanotes.model.entity.QuestionListItem; +import com.example.copykamanotes.model.vo.questionListItem.CreateQuestionListItemVO; +import com.example.copykamanotes.model.vo.questionListItem.QuestionListItemUserVO; +import com.example.copykamanotes.model.vo.questionListItem.QuestionListItemVO; +import com.example.copykamanotes.scope.RequestScopeData; +import com.example.copykamanotes.service.QuestionListItemService; +import com.example.copykamanotes.utils.ApiResponseUtils; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; + +import java.util.Collections; +import java.util.List; +import java.util.Set; + +@Slf4j +@Service +@RequiredArgsConstructor +public class QuestionListItemServiceImpl implements QuestionListItemService { + + private final QuestionListItemMapper questionListItemMapper; + private final QuestionListMapper questionListMapper; + private final RequestScopeData requestScopeData; + private final NoteMapper noteMapper; + private final UserMapper userMapper; + + @Override + public ApiResponse> useGetQuestionListItemUserVO(QuestionListItemQueryParams questionListItemQueryParams) { + + int offset = questionListItemQueryParams.getPage() * questionListItemQueryParams.getPageSize(); + int total = questionListItemMapper.countByQuestionListId(questionListItemQueryParams.getQuestionListId()); + + Pagination pagination = new Pagination(questionListItemQueryParams.getPage(), questionListItemQueryParams.getPageSize(), total); + + Integer questionListId = questionListItemQueryParams.getQuestionListId(); + + QuestionList questionList = questionListMapper.findById(questionListId); + + List questionListItem = questionListItemMapper.findByQuestionListIdPage(questionListId, questionListItemQueryParams.getPageSize(), offset); + List questionIds = questionListItem.stream().map(item -> item.getQuestion().getQuestionId()).toList(); + + final Set userFinishedQuestionIds; + + if (requestScopeData.isLogin()) { + userFinishedQuestionIds = noteMapper.filterFinishedQuestionIdsByUser(requestScopeData.getUserId(), questionIds); + } else { + userFinishedQuestionIds = Collections.emptySet(); + } + + List list = questionListItem.stream().map(item -> { + QuestionListItemUserVO questionListItemUserVO = new QuestionListItemUserVO(); + BeanUtils.copyProperties(item, questionListItemUserVO); + + QuestionListItemUserVO.UserQuestionStatus userQuestionStatus = + new QuestionListItemUserVO.UserQuestionStatus(); + + if (requestScopeData.isLogin()) { + userQuestionStatus.setFinished(userFinishedQuestionIds.contains(item.getQuestion().getQuestionId())); + } else { + userQuestionStatus.setFinished(false); + } + + questionListItemUserVO.setUserQuestionStatus(userQuestionStatus); + return questionListItemUserVO; + }).toList(); + + return ApiResponseUtils.success("获取问题列表成功", list, pagination); + } + + @Override + public ApiResponse> getQuestionListItems(Integer questionListId) { + List byQuestionListId = questionListItemMapper.findByQuestionListId(questionListId); + return ApiResponseUtils.success("获取问题列表成功", byQuestionListId); + } + + @Override + public ApiResponse createQuestionListItem(CreateQuestionListItemBody createQuestionListItemBody) { + QuestionListItem questionListItem = new QuestionListItem(); + BeanUtils.copyProperties(createQuestionListItemBody, questionListItem); + + try { + int rank = questionListItemMapper.nextRank(createQuestionListItemBody.getQuestionListId()); + questionListItem.setRank(rank); + + questionListItemMapper.insert(questionListItem); + CreateQuestionListItemVO questionVO = new CreateQuestionListItemVO(); + questionVO.setRank(rank); + return ApiResponseUtils.success("创建问题列表成功", questionVO); + } catch (Exception e) { + return ApiResponseUtils.error("创建问题列表失败"); + } + } + + @Override + public ApiResponse deleteQuestionListItem(Integer questionListId, Integer questionId) { + try { + questionListItemMapper.deleteByQuestionListIdAndQuestionId(questionListId, questionId); + return ApiResponseUtils.success("删除问题列表成功"); + } catch (Exception e) { + return ApiResponseUtils.error("删除问题列表失败"); + } + } + + @Override + public ApiResponse sortQuestionListItem(SortQuestionListItemBody body) { + List questionIds = body.getQuestionIds(); + Integer questionListId = body.getQuestionListId(); + + try { + for (int i = 0; i < questionIds.size(); i++) { + QuestionListItem questionListItem = new QuestionListItem(); + questionListItem.setQuestionId(questionIds.get(i)); + questionListItem.setQuestionListId(questionListId); + questionListItem.setRank(i + 1); + questionListItemMapper.updateQuestionRank(questionListItem); + } + return ApiResponseUtils.success("排序问题列表成功"); + } catch (Exception e) { + return ApiResponseUtils.error("排序问题列表失败"); + } + } +} diff --git a/src/main/java/com/example/copykamanotes/service/impl/QuestionListServiceImpl.java b/src/main/java/com/example/copykamanotes/service/impl/QuestionListServiceImpl.java new file mode 100644 index 0000000..eeaac97 --- /dev/null +++ b/src/main/java/com/example/copykamanotes/service/impl/QuestionListServiceImpl.java @@ -0,0 +1,80 @@ +package com.example.copykamanotes.service.impl; + +import com.example.copykamanotes.mapper.QuestionListItemMapper; +import com.example.copykamanotes.mapper.QuestionListMapper; +import com.example.copykamanotes.model.base.ApiResponse; +import com.example.copykamanotes.model.base.EmptyVO; +import com.example.copykamanotes.model.dto.questionList.CreateQuestionListBody; +import com.example.copykamanotes.model.dto.questionList.UpdateQuestionListBody; +import com.example.copykamanotes.model.entity.QuestionList; +import com.example.copykamanotes.model.vo.questionList.CreateQuestionListVO; +import com.example.copykamanotes.service.QuestionListService; +import com.example.copykamanotes.utils.ApiResponseUtils; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; +import java.util.List; + +@Service +@RequiredArgsConstructor +public class QuestionListServiceImpl implements QuestionListService { + + private final QuestionListMapper questionListMapper; + private final QuestionListItemMapper questionListItemMapper; + + @Override + public ApiResponse getQuestionList(Integer questionListId) { + return ApiResponseUtils.success("获取问题列表成功", questionListMapper.findById(questionListId)); + } + + @Override + public ApiResponse> getQuestionLists() { + return ApiResponseUtils.success("获取问题列表成功", questionListMapper.findAll()); + } + + @Override + public ApiResponse createQuestionList(CreateQuestionListBody body) { + QuestionList questionList = new QuestionList(); + BeanUtils.copyProperties(body, questionList); + + try { + questionListMapper.insert(questionList); + CreateQuestionListVO questionVO = new CreateQuestionListVO(); + questionVO.setQuestionListId(questionList.getQuestionListId()); + return ApiResponseUtils.success("创建问题列表成功", questionVO); + } catch (Exception e) { + return ApiResponseUtils.error("创建问题列表失败"); + } + } + + @Override + public ApiResponse deleteQuestionList(Integer questionListId) { + QuestionList questionList = questionListMapper.findById(questionListId); + + if (questionList == null) { + return ApiResponseUtils.error("问题列表不存在"); + } + + try { + questionListMapper.deleteById(questionListId); + questionListItemMapper.deleteByQuestionListId(questionListId); + return ApiResponseUtils.success("删除问题列表成功"); + } catch (Exception e) { + return ApiResponseUtils.error("删除问题列表失败"); + } + } + + @Override + public ApiResponse updateQuestionList(Integer questionListId, UpdateQuestionListBody body) { + QuestionList questionList = new QuestionList(); + BeanUtils.copyProperties(body, questionList); + questionList.setQuestionListId(questionListId); + + try { + questionListMapper.update(questionList); + return ApiResponseUtils.success("更新问题列表成功"); + } catch (Exception e) { + return ApiResponseUtils.error("更新问题列表失败"); + } + } +} diff --git a/src/main/java/com/example/copykamanotes/service/impl/QuestionServiceImpl.java b/src/main/java/com/example/copykamanotes/service/impl/QuestionServiceImpl.java index bd8bdd3..9c75c75 100644 --- a/src/main/java/com/example/copykamanotes/service/impl/QuestionServiceImpl.java +++ b/src/main/java/com/example/copykamanotes/service/impl/QuestionServiceImpl.java @@ -1,64 +1,198 @@ package com.example.copykamanotes.service.impl; +import com.example.copykamanotes.mapper.CategoryMapper; +import com.example.copykamanotes.mapper.NoteMapper; +import com.example.copykamanotes.mapper.QuestionMapper; import com.example.copykamanotes.model.base.ApiResponse; import com.example.copykamanotes.model.base.EmptyVO; +import com.example.copykamanotes.model.base.Pagination; import com.example.copykamanotes.model.dto.question.CreateQuestionBody; import com.example.copykamanotes.model.dto.question.QuestionQueryParam; import com.example.copykamanotes.model.dto.question.SearchQuestionBody; import com.example.copykamanotes.model.dto.question.UpdateQuestionBody; +import com.example.copykamanotes.model.entity.Category; +import com.example.copykamanotes.model.entity.Note; import com.example.copykamanotes.model.entity.Question; import com.example.copykamanotes.model.vo.question.CreateQuestionVO; import com.example.copykamanotes.model.vo.question.QuestionNoteVO; +import com.example.copykamanotes.model.vo.question.QuestionUserVO; import com.example.copykamanotes.model.vo.question.QuestionVO; +import com.example.copykamanotes.scope.RequestScopeData; import com.example.copykamanotes.service.QuestionService; +import com.example.copykamanotes.utils.ApiResponseUtils; +import com.example.copykamanotes.utils.PaginationUtils; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; +import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; @Service +@RequiredArgsConstructor public class QuestionServiceImpl implements QuestionService { + + private final QuestionMapper questionMapper; + private final CategoryMapper categoryMapper; + private final RequestScopeData requestScopeData; + private final NoteMapper noteMapper; + @Override public Question findById(Integer questionId) { - return null; + return questionMapper.findById(questionId); } public Map getQuestionMapByIds(List questionIds) { - return null; + if (questionIds.isEmpty()) + return Collections.emptyMap(); + + List questions = questionMapper.findByIdBatch(questionIds); + + return questions.stream().collect(Collectors.toMap(Question::getQuestionId, question -> question)); } @Override public ApiResponse> getQuestions(QuestionQueryParam queryParam) { - return null; + int offset = PaginationUtils.calculateOffset(queryParam.getPage(), queryParam.getPageSize()); + int total = questionMapper.countByQueryParam(queryParam); + + Pagination pagination = new Pagination(queryParam.getPage(), queryParam.getPageSize(), total); + + List questions = questionMapper.findByQueryParam(queryParam, queryParam.getPageSize(), offset); + + List questionVOS = questions.stream().map(question -> { + QuestionVO questionVO = new QuestionVO(); + BeanUtils.copyProperties(question, questionVO); + return questionVO; + }).toList(); + + return ApiResponseUtils.success("获取问题列表成功", questionVOS, pagination); } @Override public ApiResponse createQuestion(CreateQuestionBody body) { - return null; + + Category category = categoryMapper.findById(body.getCategoryId()); + if (category == null) { + return ApiResponseUtils.error("分类 Id 不存在"); + } + + Question question = new Question(); + BeanUtils.copyProperties(body, question); + + try { + questionMapper.insert(question); + CreateQuestionVO createQuestionVO = new CreateQuestionVO(); + createQuestionVO.setQuestionId(question.getQuestionId()); + return ApiResponseUtils.success("创建问题成功", createQuestionVO); + } catch (Exception e) { + return ApiResponseUtils.error("创建问题失败"); + } } @Override public ApiResponse updateQuestion(Integer questionId, UpdateQuestionBody body) { - return null; + Question question = new Question(); + BeanUtils.copyProperties(body, question); + question.setQuestionId(questionId); + + try { + questionMapper.update(question); + return ApiResponseUtils.success("更新问题成功"); + } catch (Exception e) { + return ApiResponseUtils.error("更新问题失败"); + } } @Override public ApiResponse deleteQuestion(Integer questionId) { - return null; + try { + if (questionMapper.deleteById(questionId) > 0) + return ApiResponseUtils.success("删除问题成功"); + else + return ApiResponseUtils.error("删除问题失败"); + } catch (Exception e) { + return ApiResponseUtils.error("删除问题失败"); + } } @Override - public ApiResponse> userGetQuestions(QuestionQueryParam queryParam) { - return null; + public ApiResponse> userGetQuestions(QuestionQueryParam queryParam) { + + int offset = PaginationUtils.calculateOffset(queryParam.getPage(), queryParam.getPageSize()); + int total = questionMapper.countByQueryParam(queryParam); + Pagination pagination = new Pagination(queryParam.getPage(), queryParam.getPageSize(), total); + + List questions = questionMapper.findByQueryParam(queryParam, queryParam.getPageSize(), offset); + List questionIds = questions.stream().map(Question::getQuestionId).toList(); + + Set userFinishedQuestionIds; + + if (requestScopeData.isLogin() && requestScopeData.getUserId() != null) { + userFinishedQuestionIds = noteMapper.filterFinishedQuestionIdsByUser(requestScopeData.getUserId(), questionIds); + } else { + userFinishedQuestionIds = Collections.emptySet(); + } + + List questionUserVOS = questions.stream().map(question -> { + QuestionUserVO questionUserVO = new QuestionUserVO(); + QuestionUserVO.UserQuestionStatus userQuestionStatus = new QuestionUserVO.UserQuestionStatus(); + + if (userFinishedQuestionIds.contains(question.getQuestionId())) { + userQuestionStatus.setFinished(true); + } + + BeanUtils.copyProperties(question, questionUserVO); + + questionUserVO.setUserQuestionStatus(userQuestionStatus); + return questionUserVO; + }).toList(); + + return ApiResponseUtils.success("获取问题列表成功", questionUserVOS, pagination); } @Override public ApiResponse userGetQuestion(Integer questionId) { - return null; + + Question question = questionMapper.findById(questionId); + if (question == null) { + return ApiResponseUtils.error("问题不存在"); + } + + QuestionNoteVO questionNoteVO = new QuestionNoteVO(); + QuestionNoteVO.UserNote userNote = new QuestionNoteVO.UserNote(); + + if (requestScopeData.isLogin() && requestScopeData.getUserId() != null) { + Note note = noteMapper.findByAuthorIdAndQuestionId(requestScopeData.getUserId(), questionId); + if (note != null) { + userNote.setFinished(true); + BeanUtils.copyProperties(note, userNote); + } + } + + BeanUtils.copyProperties(question, questionNoteVO); + questionNoteVO.setUserNote(userNote); + + questionMapper.incrementViewCount(questionId); + + return ApiResponseUtils.success("获取问题成功", questionNoteVO); } @Override public ApiResponse> searchQuestion(SearchQuestionBody body) { - return null; + String keyword = body.getKeyword(); + + List questionList = questionMapper.findByKeyword(keyword); + + List questionVOList = questionList.stream().map(question -> { + QuestionVO questionVO = new QuestionVO(); + BeanUtils.copyProperties(question, questionVO); + return questionVO; + }).toList(); + + return ApiResponseUtils.success("搜索成功", questionVOList); } } diff --git a/src/main/java/com/example/copykamanotes/service/impl/RedisServiceImpl.java b/src/main/java/com/example/copykamanotes/service/impl/RedisServiceImpl.java index 8f023c9..b106106 100644 --- a/src/main/java/com/example/copykamanotes/service/impl/RedisServiceImpl.java +++ b/src/main/java/com/example/copykamanotes/service/impl/RedisServiceImpl.java @@ -1,14 +1,16 @@ package com.example.copykamanotes.service.impl; import com.example.copykamanotes.service.RedisService; +import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; @Service +@RequiredArgsConstructor public class RedisServiceImpl implements RedisService { - @Autowired - private RedisTemplate redisTemplate; + + private final RedisTemplate redisTemplate; @Override public void set(String key, Object value) { diff --git a/src/main/java/com/example/copykamanotes/service/impl/SearchServiceImpl.java b/src/main/java/com/example/copykamanotes/service/impl/SearchServiceImpl.java new file mode 100644 index 0000000..49cc86d --- /dev/null +++ b/src/main/java/com/example/copykamanotes/service/impl/SearchServiceImpl.java @@ -0,0 +1,102 @@ +package com.example.copykamanotes.service.impl; + +import com.example.copykamanotes.mapper.NoteMapper; +import com.example.copykamanotes.mapper.UserMapper; +import com.example.copykamanotes.model.base.ApiResponse; +import com.example.copykamanotes.model.entity.Note; +import com.example.copykamanotes.model.entity.User; +import com.example.copykamanotes.service.SearchService; +import com.example.copykamanotes.utils.ApiResponseUtils; +import com.example.copykamanotes.utils.SearchUtils; +import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +@Service +@RequiredArgsConstructor +public class SearchServiceImpl implements SearchService { + + private final NoteMapper noteMapper; + private final UserMapper userMapper; + private final RedisTemplate redisTemplate; + + private static final String NOTE_SEARCH_CACHE_KEY = "search:note:%s:%d:%d"; + private static final String USER_SEARCH_CACHE_KEY = "search:user:%s:%d:%d"; + private static final String NOTE_TAG_SEARCH_CACHE_KEY = "search:note:tag:%s:%s:%d:%d"; + private static final long CACHE_EXPIRE_TIME = 30; // 分钟 + + @Override + public ApiResponse> searchNote(String keyword, int page, int pageSize) { + try { + String cacheKey = String.format(NOTE_SEARCH_CACHE_KEY, keyword, page, pageSize); + + List cacheResult = (List) redisTemplate.opsForValue().get(cacheKey); + if (cacheResult != null) { + return ApiResponseUtils.success("搜索成功", cacheResult); + } + + keyword = SearchUtils.preprocessKeyword(keyword); + + int offset = (page - 1) * pageSize; + + List notes = noteMapper.searchNotes(keyword, pageSize, offset); + + redisTemplate.opsForValue().set(cacheKey, notes, CACHE_EXPIRE_TIME, TimeUnit.MINUTES); + + return ApiResponseUtils.success("搜索成功", notes); + } catch (Exception e) { + return ApiResponseUtils.error("搜索失败"); + } + } + + @Override + public ApiResponse> searchUsers(String keyword, int page, int pageSize) { + try { + String cacheKey = String.format(NOTE_SEARCH_CACHE_KEY, keyword, page, pageSize); + + List cacheResult = (List) redisTemplate.opsForValue().get(cacheKey); + if (cacheResult != null) { + return ApiResponseUtils.success("搜索成功", cacheResult); + } + + keyword = SearchUtils.preprocessKeyword(keyword); + + int offset = (page - 1) * pageSize; + + List users = userMapper.searchUsers(keyword, pageSize, offset); + + redisTemplate.opsForValue().set(cacheKey, users, CACHE_EXPIRE_TIME, TimeUnit.MINUTES); + + return ApiResponseUtils.success("搜索成功", users); + } catch (Exception e) { + return ApiResponseUtils.error("搜索失败"); + } + } + + @Override + public ApiResponse> searchNotesByTag(String keyword, String tag, int page, int pageSize) { + try { + String cacheKey = String.format(NOTE_SEARCH_CACHE_KEY, keyword, page, pageSize); + + List cachedResult = (List) redisTemplate.opsForValue().get(cacheKey); + if (cachedResult != null) { + return ApiResponseUtils.success("搜索成功", cachedResult); + } + + keyword = SearchUtils.preprocessKeyword(keyword); + + int offset = (page - 1) * pageSize; + + List notes = noteMapper.searchNotesByTag(keyword, tag, pageSize, offset); + + redisTemplate.opsForValue().set(cacheKey, notes, CACHE_EXPIRE_TIME, TimeUnit.MINUTES); + + return ApiResponseUtils.success("搜索成功", notes); + } catch (Exception e) { + return ApiResponseUtils.error("搜索失败"); + } + } +} diff --git a/src/main/java/com/example/copykamanotes/service/impl/UploadServiceImpl.java b/src/main/java/com/example/copykamanotes/service/impl/UploadServiceImpl.java index a19e113..3eca7b2 100644 --- a/src/main/java/com/example/copykamanotes/service/impl/UploadServiceImpl.java +++ b/src/main/java/com/example/copykamanotes/service/impl/UploadServiceImpl.java @@ -5,15 +5,16 @@ import com.example.copykamanotes.model.vo.upload.ImageVO; import com.example.copykamanotes.service.FileService; import com.example.copykamanotes.service.UploadService; import com.example.copykamanotes.utils.ApiResponseUtils; +import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; @Service +@RequiredArgsConstructor public class UploadServiceImpl implements UploadService { - @Autowired - private FileService fileService; + private final FileService fileService; @Override public ApiResponse uploadImage(MultipartFile file) { diff --git a/src/main/java/com/example/copykamanotes/service/impl/UserServiceImpl.java b/src/main/java/com/example/copykamanotes/service/impl/UserServiceImpl.java index affba6a..3b3a5a9 100644 --- a/src/main/java/com/example/copykamanotes/service/impl/UserServiceImpl.java +++ b/src/main/java/com/example/copykamanotes/service/impl/UserServiceImpl.java @@ -20,9 +20,9 @@ import com.example.copykamanotes.service.UserService; import com.example.copykamanotes.utils.ApiResponseUtils; import com.example.copykamanotes.utils.JwtUtil; import com.example.copykamanotes.utils.PaginationUtils; +import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; import org.springframework.beans.BeanUtils; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -31,30 +31,19 @@ import org.springframework.web.multipart.MultipartFile; import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.stream.Collectors; @Log4j2 @Service +@RequiredArgsConstructor public class UserServiceImpl implements UserService { - @Autowired - private UserMapper userMapper; - - @Autowired - private PasswordEncoder passwordEncoder; - - @Autowired - private JwtUtil jwtUtil; - - @Autowired - private RequestScopeData requestScopeData; - - @Autowired - private FileService fileService; - - @Autowired - private EmailService emailService; + private final UserMapper userMapper; + private final PasswordEncoder passwordEncoder; + private final JwtUtil jwtUtil; + private final RequestScopeData requestScopeData; + private final FileService fileService; + private final EmailService emailService; @Override @Transactional(rollbackFor = Exception.class) @@ -199,7 +188,7 @@ public class UserServiceImpl implements UserService { public Map getUserMapByIds(List authorIds) { if (authorIds.isEmpty()) return Collections.emptyMap(); - List users = userMapper.findByIds(authorIds); + List users = userMapper.findByIdBatch(authorIds); return users.stream().collect(Collectors.toMap(User::getUserId, user -> user)); } @@ -233,33 +222,4 @@ public class UserServiceImpl implements UserService { return ApiResponseUtils.error("上传失败"); } } - - @Override - public ApiResponse updateUserPassword(String oldPassword, String newPassword) { - Long userId = requestScopeData.getUserId(); - - if (userId == null) { - return ApiResponseUtils.error("未登录"); - } - - User user = null; - user = userMapper.findById(userId); - if (user == null || !passwordEncoder.matches(oldPassword, user.getPassword())) { - return ApiResponseUtils.error("旧密码错误"); - } - - if (Objects.equals(oldPassword, newPassword)) { - return ApiResponseUtils.error("新密码不能与旧密码相同"); - } - - user.setPassword(passwordEncoder.encode(newPassword)); - - try { - userMapper.updatePassword(user.getUserId(), user.getPassword()); - return ApiResponseUtils.success("更新密码成功"); - } catch (Exception e) { - log.error("更新密码失败", e); - return ApiResponseUtils.error("更新密码失败"); - } - } }