feat(question): 添加问题相关功能- 新增题单相关实体和接口

- 实现问题列表获取、问题创建、更新和删除功能
- 添加用户问题列表获取和单个问题获取功能
- 实现问题搜索功能
- 优化消息服务实现
- 重构部分现有服务的代码结构
This commit is contained in:
LingandRX 2025-05-13 22:05:45 +08:00
parent 6d8e44627f
commit 0244267ab7
23 changed files with 891 additions and 141 deletions

View File

@ -71,11 +71,4 @@ public class UserController {
) { ) {
return userService.getUserList(userQueryParam); return userService.getUserList(userQueryParam);
} }
@PostMapping("/users/resetPassword")
public ApiResponse<UserVO> updateUserPassword(
@RequestBody UserRestPasswordRequest userRestPasswordRequest
) {
return userService.updateUserPassword(userRestPasswordRequest.getOldPassword(), userRestPasswordRequest.getNewPassword());
}
} }

View File

@ -1,9 +1,84 @@
package com.example.copykamanotes.mapper; 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.entity.Message;
import com.example.copykamanotes.model.vo.message.UnreadCountByType;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 消息Mapper接口
*/
@Mapper @Mapper
public interface MessageMapper { public interface MessageMapper {
/**
* 插入消息
*
* @param message 消息实体
* @return 影响行数
*/
int insert(Message message); int insert(Message message);
/**
* 根据参数查询消息列表
*
* @param userId 用户ID
* @param params 查询参数
* @param offset 偏移量
* @return 消息列表
*/
List<Message> 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<UnreadCountByType> countUnreadByType(@Param("userId") Long userId);
} }

View File

@ -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<QuestionList> findAll();
/**
* 更新一个题单的信息
*
* @param questionList 要更新的题单对象包含需要更新的字段
* @return 更新操作影响的行数
*/
int update(QuestionList questionList);
/**
* 根据题单ID删除题单
*
* @param questionListId 题单的唯一标识符
* @return 删除操作影响的行数
*/
int deleteById(@Param("questionListId") Integer questionListId);
}

View File

@ -10,27 +10,127 @@ import java.util.List;
@Mapper @Mapper
public interface UserMapper { public interface UserMapper {
/** /**
* 用户 * 插入新用户
* *
* @param user 用户信息 * @param user 待插入的用户对象包含用户的所有信息
*/ */
int insert(User user); int insert(User user);
User findByAccount(@Param("account") String account); /**
* 根据ID查找用户
User findByEmail(@Param("email") String email); *
* @param userId 用户ID用于查询用户信息
int updateLastLoginAt(@Param("userId") Long userId); * @return 返回用户对象如果未找到则返回null
*/
User findById(@Param("userId") Long userId); User findById(@Param("userId") Long userId);
/**
* 根据 ID 数组批量查找用户
*
* @param userIds 用户ID列表用于批量查询用户信息
* @return 返回用户列表如果未找到任何用户则返回空列表
*/
List<User> findByIdBatch(@Param("userIds") List<Long> 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<User> 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 update(User user);
int updatePassword(@Param("userId") Long userId, @Param("password") String password); /**
* 更新用户在线时间
*
* @param userId 用户ID用于标识需要更新在线时间的用户
*/
int updateLastLoginAt(@Param("userId") Long userId);
List<User> findByIds(@Param("userIds") List<Long> 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<User> 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<User> searchUsers(@Param("keyword") String keyword,
@Param("limit") int limit,
@Param("offset") int offset);
} }

View File

@ -1,4 +1,37 @@
package com.example.copykamanotes.model.entity; package com.example.copykamanotes.model.entity;
import lombok.Data;
import java.util.Date;
@Data
public class QuestionList { public class QuestionList {
/*
* 题单ID主键
*/
private Integer questionListId;
/*
* 题单名称
*/
private String name;
/**
* 题单类型
*/
private Integer type;
/*
* 题单描述
*/
private String description;
/*
* 创建时间
*/
private Date createdAt;
/*
* 更新时间
*/
private Date updatedAt;
} }

View File

@ -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.CollectionQueryParams;
import com.example.copykamanotes.model.dto.collection.CreateCollectionBody; import com.example.copykamanotes.model.dto.collection.CreateCollectionBody;
import com.example.copykamanotes.model.dto.collection.UpdateCollectionBody; 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.CollectionVO;
import com.example.copykamanotes.model.vo.collection.CreateCollectionVO; import com.example.copykamanotes.model.vo.collection.CreateCollectionVO;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;

View File

@ -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.dto.questionListItem.SortQuestionListItemBody;
import com.example.copykamanotes.model.vo.questionListItem.CreateQuestionListItemVO; import com.example.copykamanotes.model.vo.questionListItem.CreateQuestionListItemVO;
import com.example.copykamanotes.model.vo.questionListItem.QuestionListItemUserVO; import com.example.copykamanotes.model.vo.questionListItem.QuestionListItemUserVO;
import com.example.copykamanotes.model.vo.questionListItem.QuestionListItemVO;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.List; import java.util.List;
@ -15,7 +16,7 @@ import java.util.List;
public interface QuestionListItemService { public interface QuestionListItemService {
ApiResponse<List<QuestionListItemUserVO>> useGetQuestionListItemUserVO(QuestionListItemQueryParams questionListItemQueryParams); ApiResponse<List<QuestionListItemUserVO>> useGetQuestionListItemUserVO(QuestionListItemQueryParams questionListItemQueryParams);
ApiResponse<List<QuestionListItemUserVO>> getQuestionListItem(Integer questionListId); ApiResponse<List<QuestionListItemVO>> getQuestionListItems(Integer questionListId);
ApiResponse<CreateQuestionListItemVO> createQuestionListItem(CreateQuestionListItemBody createQuestionListItemBody); ApiResponse<CreateQuestionListItemVO> createQuestionListItem(CreateQuestionListItemBody createQuestionListItemBody);

View File

@ -9,6 +9,7 @@ import com.example.copykamanotes.model.dto.question.UpdateQuestionBody;
import com.example.copykamanotes.model.entity.Question; import com.example.copykamanotes.model.entity.Question;
import com.example.copykamanotes.model.vo.question.CreateQuestionVO; import com.example.copykamanotes.model.vo.question.CreateQuestionVO;
import com.example.copykamanotes.model.vo.question.QuestionNoteVO; 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.model.vo.question.QuestionVO;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -30,7 +31,7 @@ public interface QuestionService {
ApiResponse<EmptyVO> deleteQuestion(Integer questionId); ApiResponse<EmptyVO> deleteQuestion(Integer questionId);
ApiResponse<List<QuestionVO>> userGetQuestions(QuestionQueryParam queryParam); ApiResponse<List<QuestionUserVO>> userGetQuestions(QuestionQueryParam queryParam);
ApiResponse<QuestionNoteVO> userGetQuestion(Integer questionId); ApiResponse<QuestionNoteVO> userGetQuestion(Integer questionId);

View File

@ -11,5 +11,5 @@ public interface SearchService {
ApiResponse<List<User>> searchUsers(String keyword, int page, int pageSize); ApiResponse<List<User>> searchUsers(String keyword, int page, int pageSize);
ApiResponse<List<Note>> searchNotesByTag(String keyword, int page, int pageSize); ApiResponse<List<Note>> searchNotesByTag(String keyword, String tag, int page, int pageSize);
} }

View File

@ -66,8 +66,6 @@ public interface UserService {
*/ */
Map<Long, User> getUserMapByIds(List<Long> authorIds); Map<Long, User> getUserMapByIds(List<Long> authorIds);
ApiResponse<UserVO> updateUserPassword(String oldPassword, String newPassword);
/** /**
* 获取用户列表 * 获取用户列表
* @param userQueryParam 查询参数 * @param userQueryParam 查询参数

View File

@ -11,6 +11,7 @@ import com.example.copykamanotes.model.vo.category.CategoryVO;
import com.example.copykamanotes.model.vo.category.CreateCategoryVO; import com.example.copykamanotes.model.vo.category.CreateCategoryVO;
import com.example.copykamanotes.service.CategoryService; import com.example.copykamanotes.service.CategoryService;
import com.example.copykamanotes.utils.ApiResponseUtils; import com.example.copykamanotes.utils.ApiResponseUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -21,14 +22,11 @@ import java.util.List;
import java.util.Map; import java.util.Map;
@Service @Service
@RequiredArgsConstructor
public class CategoryServiceImpl implements CategoryService { public class CategoryServiceImpl implements CategoryService {
@Autowired private final CategoryMapper categoryMapper;
private CategoryMapper categoryMapper; private final QuestionMapper questionMapper;
@Autowired
private QuestionMapper questionMapper;
@Override @Override
public ApiResponse<EmptyVO> updateCategory(Integer id, UpdateCategoryBody updateCategoryBody) { public ApiResponse<EmptyVO> updateCategory(Integer id, UpdateCategoryBody updateCategoryBody) {

View File

@ -2,6 +2,7 @@ package com.example.copykamanotes.service.impl;
import com.example.copykamanotes.mapper.CollectionNoteMapper; import com.example.copykamanotes.mapper.CollectionNoteMapper;
import com.example.copykamanotes.service.CollectionNoteService; import com.example.copykamanotes.service.CollectionNoteService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -10,10 +11,10 @@ import java.util.List;
import java.util.Set; import java.util.Set;
@Service @Service
@RequiredArgsConstructor
public class CollectionNoteServiceImpl implements CollectionNoteService { public class CollectionNoteServiceImpl implements CollectionNoteService {
@Autowired private final CollectionNoteMapper collectionNoteMapper;
private CollectionNoteMapper collectionNoteMapper;
@Override @Override
public Set<Integer> findUserCollectionNoteIds(Long userId, List<Integer> noteIds) { public Set<Integer> findUserCollectionNoteIds(Long userId, List<Integer> noteIds) {

View File

@ -16,6 +16,7 @@ import com.example.copykamanotes.model.vo.collection.CreateCollectionVO;
import com.example.copykamanotes.scope.RequestScopeData; import com.example.copykamanotes.scope.RequestScopeData;
import com.example.copykamanotes.service.CollectionService; import com.example.copykamanotes.service.CollectionService;
import com.example.copykamanotes.utils.ApiResponseUtils; import com.example.copykamanotes.utils.ApiResponseUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -26,19 +27,13 @@ import java.util.List;
import java.util.Set; import java.util.Set;
@Service @Service
@RequiredArgsConstructor
public class CollectionServiceImpl implements CollectionService { public class CollectionServiceImpl implements CollectionService {
@Autowired private final RequestScopeData requestScopeData;
private RequestScopeData requestScopeData; private final CollectionMapper collectionMapper;
private final CollectionNoteMapper collectionNoteMapper;
@Autowired private final NoteMapper noteMapper;
private CollectionMapper collectionMapper;
@Autowired
private CollectionNoteMapper collectionNoteMapper;
@Autowired
private NoteMapper noteMapper;
@Override @Override
public ApiResponse<List<CollectionVO>> getCollection(CollectionQueryParams queryParams) { public ApiResponse<List<CollectionVO>> getCollection(CollectionQueryParams queryParams) {

View File

@ -3,6 +3,7 @@ package com.example.copykamanotes.service.impl;
import com.example.copykamanotes.mapper.EmailVerifyCodeMapper; import com.example.copykamanotes.mapper.EmailVerifyCodeMapper;
import com.example.copykamanotes.model.entity.EmailVerifyCode; import com.example.copykamanotes.model.entity.EmailVerifyCode;
import com.example.copykamanotes.service.EmailService; import com.example.copykamanotes.service.EmailService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -17,16 +18,12 @@ import java.util.concurrent.TimeUnit;
@Slf4j @Slf4j
@Service @Service
@RequiredArgsConstructor
public class EmailServiceImpl implements EmailService { public class EmailServiceImpl implements EmailService {
@Autowired private final JavaMailSender javaMailSender;
private JavaMailSender javaMailSender; private final EmailVerifyCodeMapper emailVerifyCodeMapper;
private final RedisTemplate<String, String> redisTemplate;
@Autowired
private EmailVerifyCodeMapper emailVerifyCodeMapper;
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Value("${spring.mail.username}") @Value("${spring.mail.username}")
private String fromEmail; private String fromEmail;

View File

@ -1,50 +1,155 @@
package com.example.copykamanotes.service.impl; 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.ApiResponse;
import com.example.copykamanotes.model.base.EmptyVO; import com.example.copykamanotes.model.base.EmptyVO;
import com.example.copykamanotes.model.base.PageVO; import com.example.copykamanotes.model.base.PageVO;
import com.example.copykamanotes.model.dto.message.MessageQueryParams; 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.MessageVO;
import com.example.copykamanotes.model.vo.message.UnreadCountByType; import com.example.copykamanotes.model.vo.message.UnreadCountByType;
import com.example.copykamanotes.service.MessageService; 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 org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit;
@Service @Service
@RequiredArgsConstructor
public class MessageServiceImpl implements MessageService { public class MessageServiceImpl implements MessageService {
private final MessageMapper messageMapper;
private final UserMapper userMapper;
private final RedisTemplate<String, Object> 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 @Override
public ApiResponse<Integer> createMessage(Long receiverId, Long senderId, String type, Integer targetId, String content) { public ApiResponse<Integer> 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 @Override
public ApiResponse<EmptyVO> markAsRead(Integer messageId) { public ApiResponse<EmptyVO> markAsRead(Integer messageId) {
return null; Long currentUserId = SecurityUtils.getCurrentUserId();
messageMapper.markAsRead(messageId, currentUserId);
clearMessageCache(currentUserId);
return ApiResponse.success();
} }
@Override @Override
public ApiResponse<EmptyVO> markAllAsRead() { public ApiResponse<EmptyVO> markAllAsRead() {
return null; Long currentUserId = SecurityUtils.getCurrentUserId();
messageMapper.markAllAsRead(currentUserId);
clearMessageCache(currentUserId);
return ApiResponse.success();
} }
@Override @Override
public ApiResponse<EmptyVO> deleteMessage(Integer messageId) { public ApiResponse<EmptyVO> deleteMessage(Integer messageId) {
return null; Long currentUserId = SecurityUtils.getCurrentUserId();
messageMapper.deleteMessage(messageId, currentUserId);
return ApiResponse.success();
} }
@Override @Override
public ApiResponse<Integer> getUnreadCount() { public ApiResponse<Integer> 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 @Override
public ApiResponse<List<UnreadCountByType>> getUnreadCountByType() { public ApiResponse<List<UnreadCountByType>> getUnreadCountByType() {
return null; Long currentUserId = SecurityUtils.getCurrentUserId();
String cacheKey = UNREAD_COUNT_BY_TYPE_KEY + currentUserId;
@SuppressWarnings("unchecked")
List<UnreadCountByType> result = (List<UnreadCountByType>) redisTemplate.opsForValue().get(cacheKey);
if (result == null) {
result = messageMapper.countUnreadByType(currentUserId);
redisTemplate.opsForValue().set(cacheKey, result, 5, TimeUnit.MINUTES);
}
return ApiResponse.success(result);
} }
@Override @Override
public ApiResponse<PageVO<MessageVO>> getMessages(MessageQueryParams params) { public ApiResponse<PageVO<MessageVO>> getMessages(MessageQueryParams params) {
return null;
Long currentUserId = SecurityUtils.getCurrentUserId();
int total = messageMapper.countByParams(currentUserId, params);
int offset = (params.getPage() - 1) * params.getPageSize();
List<Message> messages = messageMapper.selectByParams(currentUserId, params, offset);
List<MessageVO> 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<MessageVO> 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);
} }
} }

View File

@ -17,34 +17,24 @@ import com.example.copykamanotes.service.*;
import com.example.copykamanotes.utils.ApiResponseUtils; import com.example.copykamanotes.utils.ApiResponseUtils;
import com.example.copykamanotes.utils.MarkdownUtils; import com.example.copykamanotes.utils.MarkdownUtils;
import com.example.copykamanotes.utils.PaginationUtils; import com.example.copykamanotes.utils.PaginationUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Service @Service
@RequiredArgsConstructor
public class NoteServiceImpl implements NoteService { public class NoteServiceImpl implements NoteService {
@Autowired private final NoteMapper noteMapper;
private NoteMapper noteMapper; private final UserService userService;
private final QuestionService questionService;
@Autowired private final NoteLikeService noteLikeService;
private UserService userService; private final RequestScopeData requestScopeData;
private final CategoryService categoryService;
@Autowired private final QuestionMapper questionMapper;
private QuestionService questionService;
@Autowired
private NoteLikeService noteLikeService;
@Autowired
private RequestScopeData requestScopeData;
@Autowired
private CategoryService categoryService;
@Autowired
private QuestionMapper questionMapper;
@Override @Override
public ApiResponse<List<NoteVO>> getNotes(NoteQueryParams noteQueryParams) { public ApiResponse<List<NoteVO>> getNotes(NoteQueryParams noteQueryParams) {

View File

@ -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<List<QuestionListItemUserVO>> 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<QuestionListItemVO> questionListItem = questionListItemMapper.findByQuestionListIdPage(questionListId, questionListItemQueryParams.getPageSize(), offset);
List<Integer> questionIds = questionListItem.stream().map(item -> item.getQuestion().getQuestionId()).toList();
final Set<Integer> userFinishedQuestionIds;
if (requestScopeData.isLogin()) {
userFinishedQuestionIds = noteMapper.filterFinishedQuestionIdsByUser(requestScopeData.getUserId(), questionIds);
} else {
userFinishedQuestionIds = Collections.emptySet();
}
List<QuestionListItemUserVO> 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<List<QuestionListItemVO>> getQuestionListItems(Integer questionListId) {
List<QuestionListItemVO> byQuestionListId = questionListItemMapper.findByQuestionListId(questionListId);
return ApiResponseUtils.success("获取问题列表成功", byQuestionListId);
}
@Override
public ApiResponse<CreateQuestionListItemVO> 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<EmptyVO> deleteQuestionListItem(Integer questionListId, Integer questionId) {
try {
questionListItemMapper.deleteByQuestionListIdAndQuestionId(questionListId, questionId);
return ApiResponseUtils.success("删除问题列表成功");
} catch (Exception e) {
return ApiResponseUtils.error("删除问题列表失败");
}
}
@Override
public ApiResponse<EmptyVO> sortQuestionListItem(SortQuestionListItemBody body) {
List<Integer> 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("排序问题列表失败");
}
}
}

View File

@ -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<QuestionList> getQuestionList(Integer questionListId) {
return ApiResponseUtils.success("获取问题列表成功", questionListMapper.findById(questionListId));
}
@Override
public ApiResponse<List<QuestionList>> getQuestionLists() {
return ApiResponseUtils.success("获取问题列表成功", questionListMapper.findAll());
}
@Override
public ApiResponse<CreateQuestionListVO> 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<EmptyVO> 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<EmptyVO> 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("更新问题列表失败");
}
}
}

View File

@ -1,64 +1,198 @@
package com.example.copykamanotes.service.impl; 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.ApiResponse;
import com.example.copykamanotes.model.base.EmptyVO; 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.CreateQuestionBody;
import com.example.copykamanotes.model.dto.question.QuestionQueryParam; import com.example.copykamanotes.model.dto.question.QuestionQueryParam;
import com.example.copykamanotes.model.dto.question.SearchQuestionBody; import com.example.copykamanotes.model.dto.question.SearchQuestionBody;
import com.example.copykamanotes.model.dto.question.UpdateQuestionBody; 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.entity.Question;
import com.example.copykamanotes.model.vo.question.CreateQuestionVO; import com.example.copykamanotes.model.vo.question.CreateQuestionVO;
import com.example.copykamanotes.model.vo.question.QuestionNoteVO; 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.model.vo.question.QuestionVO;
import com.example.copykamanotes.scope.RequestScopeData;
import com.example.copykamanotes.service.QuestionService; 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 org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@Service @Service
@RequiredArgsConstructor
public class QuestionServiceImpl implements QuestionService { public class QuestionServiceImpl implements QuestionService {
private final QuestionMapper questionMapper;
private final CategoryMapper categoryMapper;
private final RequestScopeData requestScopeData;
private final NoteMapper noteMapper;
@Override @Override
public Question findById(Integer questionId) { public Question findById(Integer questionId) {
return null; return questionMapper.findById(questionId);
} }
public Map<Integer, Question> getQuestionMapByIds(List<Integer> questionIds) { public Map<Integer, Question> getQuestionMapByIds(List<Integer> questionIds) {
return null; if (questionIds.isEmpty())
return Collections.emptyMap();
List<Question> questions = questionMapper.findByIdBatch(questionIds);
return questions.stream().collect(Collectors.toMap(Question::getQuestionId, question -> question));
} }
@Override @Override
public ApiResponse<List<QuestionVO>> getQuestions(QuestionQueryParam queryParam) { public ApiResponse<List<QuestionVO>> 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<Question> questions = questionMapper.findByQueryParam(queryParam, queryParam.getPageSize(), offset);
List<QuestionVO> questionVOS = questions.stream().map(question -> {
QuestionVO questionVO = new QuestionVO();
BeanUtils.copyProperties(question, questionVO);
return questionVO;
}).toList();
return ApiResponseUtils.success("获取问题列表成功", questionVOS, pagination);
} }
@Override @Override
public ApiResponse<CreateQuestionVO> createQuestion(CreateQuestionBody body) { public ApiResponse<CreateQuestionVO> 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 @Override
public ApiResponse<EmptyVO> updateQuestion(Integer questionId, UpdateQuestionBody body) { public ApiResponse<EmptyVO> 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 @Override
public ApiResponse<EmptyVO> deleteQuestion(Integer questionId) { public ApiResponse<EmptyVO> 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 @Override
public ApiResponse<List<QuestionVO>> userGetQuestions(QuestionQueryParam queryParam) { public ApiResponse<List<QuestionUserVO>> userGetQuestions(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<Question> questions = questionMapper.findByQueryParam(queryParam, queryParam.getPageSize(), offset);
List<Integer> questionIds = questions.stream().map(Question::getQuestionId).toList();
Set<Integer> userFinishedQuestionIds;
if (requestScopeData.isLogin() && requestScopeData.getUserId() != null) {
userFinishedQuestionIds = noteMapper.filterFinishedQuestionIdsByUser(requestScopeData.getUserId(), questionIds);
} else {
userFinishedQuestionIds = Collections.emptySet();
}
List<QuestionUserVO> 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 @Override
public ApiResponse<QuestionNoteVO> userGetQuestion(Integer questionId) { public ApiResponse<QuestionNoteVO> 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 @Override
public ApiResponse<List<QuestionVO>> searchQuestion(SearchQuestionBody body) { public ApiResponse<List<QuestionVO>> searchQuestion(SearchQuestionBody body) {
return null; String keyword = body.getKeyword();
List<Question> questionList = questionMapper.findByKeyword(keyword);
List<QuestionVO> questionVOList = questionList.stream().map(question -> {
QuestionVO questionVO = new QuestionVO();
BeanUtils.copyProperties(question, questionVO);
return questionVO;
}).toList();
return ApiResponseUtils.success("搜索成功", questionVOList);
} }
} }

View File

@ -1,14 +1,16 @@
package com.example.copykamanotes.service.impl; package com.example.copykamanotes.service.impl;
import com.example.copykamanotes.service.RedisService; import com.example.copykamanotes.service.RedisService;
import lombok.RequiredArgsConstructor;
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.Service; import org.springframework.stereotype.Service;
@Service @Service
@RequiredArgsConstructor
public class RedisServiceImpl implements RedisService { public class RedisServiceImpl implements RedisService {
@Autowired
private RedisTemplate<String, Object> redisTemplate; private final RedisTemplate<String, Object> redisTemplate;
@Override @Override
public void set(String key, Object value) { public void set(String key, Object value) {

View File

@ -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<String, Object> 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<List<Note>> searchNote(String keyword, int page, int pageSize) {
try {
String cacheKey = String.format(NOTE_SEARCH_CACHE_KEY, keyword, page, pageSize);
List<Note> cacheResult = (List<Note>) redisTemplate.opsForValue().get(cacheKey);
if (cacheResult != null) {
return ApiResponseUtils.success("搜索成功", cacheResult);
}
keyword = SearchUtils.preprocessKeyword(keyword);
int offset = (page - 1) * pageSize;
List<Note> 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<List<User>> searchUsers(String keyword, int page, int pageSize) {
try {
String cacheKey = String.format(NOTE_SEARCH_CACHE_KEY, keyword, page, pageSize);
List<User> cacheResult = (List<User>) redisTemplate.opsForValue().get(cacheKey);
if (cacheResult != null) {
return ApiResponseUtils.success("搜索成功", cacheResult);
}
keyword = SearchUtils.preprocessKeyword(keyword);
int offset = (page - 1) * pageSize;
List<User> 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<List<Note>> searchNotesByTag(String keyword, String tag, int page, int pageSize) {
try {
String cacheKey = String.format(NOTE_SEARCH_CACHE_KEY, keyword, page, pageSize);
List<Note> cachedResult = (List<Note>) redisTemplate.opsForValue().get(cacheKey);
if (cachedResult != null) {
return ApiResponseUtils.success("搜索成功", cachedResult);
}
keyword = SearchUtils.preprocessKeyword(keyword);
int offset = (page - 1) * pageSize;
List<Note> 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("搜索失败");
}
}
}

View File

@ -5,15 +5,16 @@ import com.example.copykamanotes.model.vo.upload.ImageVO;
import com.example.copykamanotes.service.FileService; import com.example.copykamanotes.service.FileService;
import com.example.copykamanotes.service.UploadService; import com.example.copykamanotes.service.UploadService;
import com.example.copykamanotes.utils.ApiResponseUtils; import com.example.copykamanotes.utils.ApiResponseUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
@Service @Service
@RequiredArgsConstructor
public class UploadServiceImpl implements UploadService { public class UploadServiceImpl implements UploadService {
@Autowired private final FileService fileService;
private FileService fileService;
@Override @Override
public ApiResponse<ImageVO> uploadImage(MultipartFile file) { public ApiResponse<ImageVO> uploadImage(MultipartFile file) {

View File

@ -20,9 +20,9 @@ import com.example.copykamanotes.service.UserService;
import com.example.copykamanotes.utils.ApiResponseUtils; import com.example.copykamanotes.utils.ApiResponseUtils;
import com.example.copykamanotes.utils.JwtUtil; import com.example.copykamanotes.utils.JwtUtil;
import com.example.copykamanotes.utils.PaginationUtils; import com.example.copykamanotes.utils.PaginationUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -31,30 +31,19 @@ import org.springframework.web.multipart.MultipartFile;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Log4j2 @Log4j2
@Service @Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService { public class UserServiceImpl implements UserService {
@Autowired private final UserMapper userMapper;
private UserMapper userMapper; private final PasswordEncoder passwordEncoder;
private final JwtUtil jwtUtil;
@Autowired private final RequestScopeData requestScopeData;
private PasswordEncoder passwordEncoder; private final FileService fileService;
private final EmailService emailService;
@Autowired
private JwtUtil jwtUtil;
@Autowired
private RequestScopeData requestScopeData;
@Autowired
private FileService fileService;
@Autowired
private EmailService emailService;
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@ -199,7 +188,7 @@ public class UserServiceImpl implements UserService {
public Map<Long, User> getUserMapByIds(List<Long> authorIds) { public Map<Long, User> getUserMapByIds(List<Long> authorIds) {
if (authorIds.isEmpty()) return Collections.emptyMap(); if (authorIds.isEmpty()) return Collections.emptyMap();
List<User> users = userMapper.findByIds(authorIds); List<User> users = userMapper.findByIdBatch(authorIds);
return users.stream().collect(Collectors.toMap(User::getUserId, user -> user)); return users.stream().collect(Collectors.toMap(User::getUserId, user -> user));
} }
@ -233,33 +222,4 @@ public class UserServiceImpl implements UserService {
return ApiResponseUtils.error("上传失败"); return ApiResponseUtils.error("上传失败");
} }
} }
@Override
public ApiResponse<UserVO> 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("更新密码失败");
}
}
} }