接口优化

This commit is contained in:
2025-09-08 17:54:12 +08:00
parent e20030f10d
commit d42d689bd7
84 changed files with 6403 additions and 4310 deletions
@@ -5,27 +5,41 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.emotion.common.BasePageRequest;
import com.emotion.common.PageResult;
import com.emotion.dto.request.achievement.AchievementCreateRequest;
import com.emotion.dto.request.achievement.AchievementPageRequest;
import com.emotion.dto.request.achievement.AchievementUpdateRequest;
import com.emotion.dto.response.achievement.AchievementResponse;
import com.emotion.entity.Achievement;
import com.emotion.mapper.AchievementMapper;
import com.emotion.service.AchievementService;
import com.emotion.util.SnowflakeIdGenerator;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;
/**
* 成就服务实现类
*
* @author emotion-museum
* @date 2025-07-23
* @date 2025-09-08
*/
@Service
public class AchievementServiceImpl extends ServiceImpl<AchievementMapper, Achievement> implements AchievementService {
@Autowired
private SnowflakeIdGenerator snowflakeIdGenerator;
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@Override
public IPage<Achievement> getPage(BasePageRequest request) {
public IPage<Achievement> getPage(AchievementPageRequest request) {
Page<Achievement> page = new Page<>(request.getCurrent(), request.getSize());
LambdaQueryWrapper<Achievement> wrapper = new LambdaQueryWrapper<>();
@@ -35,6 +49,30 @@ public class AchievementServiceImpl extends ServiceImpl<AchievementMapper, Achie
.or().like(Achievement::getDescription, request.getKeyword()));
}
// 分类筛选
if (StringUtils.hasText(request.getCategory())) {
wrapper.eq(Achievement::getCategory, request.getCategory());
}
// 稀有度筛选
if (StringUtils.hasText(request.getRarity())) {
wrapper.eq(Achievement::getRarity, request.getRarity());
}
// 解锁状态筛选
if (request.getUnlocked() != null) {
if (request.getUnlocked()) {
wrapper.isNotNull(Achievement::getUnlockedTime);
} else {
wrapper.isNull(Achievement::getUnlockedTime);
}
}
// 隐藏状态筛选
if (request.getHidden() != null) {
wrapper.eq(Achievement::getIsHidden, request.getHidden() ? 1 : 0);
}
wrapper.eq(Achievement::getIsDeleted, 0);
// 排序
@@ -256,4 +294,147 @@ public class AchievementServiceImpl extends ServiceImpl<AchievementMapper, Achie
.last("LIMIT " + limit);
return this.list(wrapper);
}
}
// 新增的Response相关方法实现
@Override
public PageResult<AchievementResponse> getPageWithResponse(AchievementPageRequest request) {
IPage<Achievement> page = getPage(request);
List<AchievementResponse> responses = page.getRecords().stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
PageResult<AchievementResponse> pageResult = new PageResult<>();
pageResult.setCurrent(page.getCurrent());
pageResult.setSize(page.getSize());
pageResult.setTotal(page.getTotal());
pageResult.setPages(page.getPages());
pageResult.setRecords(responses);
return pageResult;
}
@Override
public AchievementResponse getAchievementResponseById(String id) {
Achievement achievement = this.getById(id);
if (achievement == null) {
return null;
}
return convertToResponse(achievement);
}
@Override
public AchievementResponse createAchievementWithResponse(AchievementCreateRequest request) {
Achievement achievement = new Achievement();
org.springframework.beans.BeanUtils.copyProperties(request, achievement);
achievement.setId(snowflakeIdGenerator.nextIdAsString());
boolean saved = this.save(achievement);
if (!saved) {
return null;
}
return convertToResponse(achievement);
}
@Override
public AchievementResponse updateAchievementWithResponse(AchievementUpdateRequest request) {
Achievement achievement = this.getById(request.getId());
if (achievement == null) {
return null;
}
// 更新非空字段
if (request.getTitle() != null) {
achievement.setTitle(request.getTitle());
}
if (request.getDescription() != null) {
achievement.setDescription(request.getDescription());
}
if (request.getCategory() != null) {
achievement.setCategory(request.getCategory());
}
if (request.getIcon() != null) {
achievement.setIcon(request.getIcon());
}
if (request.getRarity() != null) {
achievement.setRarity(request.getRarity());
}
if (request.getConditionType() != null) {
achievement.setConditionType(request.getConditionType());
}
if (request.getConditionValue() != null) {
achievement.setConditionValue(request.getConditionValue());
}
if (request.getRewards() != null) {
achievement.setRewards(request.getRewards());
}
if (request.getIsHidden() != null) {
achievement.setIsHidden(request.getIsHidden());
}
achievement.setUpdateTime(LocalDateTime.now());
boolean updated = this.updateById(achievement);
if (!updated) {
return null;
}
return convertToResponse(achievement);
}
@Override
public List<AchievementResponse> getByCategoryWithResponse(String category) {
List<Achievement> achievements = getByCategory(category);
return achievements.stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
}
@Override
public List<AchievementResponse> getByRarityWithResponse(String rarity) {
List<Achievement> achievements = getByRarity(rarity);
return achievements.stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
}
@Override
public List<AchievementResponse> getUnlockedAchievementsWithResponse() {
List<Achievement> achievements = getUnlockedAchievements();
return achievements.stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
}
@Override
public List<AchievementResponse> getLockedAchievementsWithResponse() {
List<Achievement> achievements = getLockedAchievements();
return achievements.stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
}
@Override
public List<AchievementResponse> getRecentlyUnlockedWithResponse(Integer limit) {
List<Achievement> achievements = getRecentlyUnlocked(limit);
return achievements.stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
}
/**
* 转换为响应对象
*/
private AchievementResponse convertToResponse(Achievement achievement) {
AchievementResponse response = new AchievementResponse();
org.springframework.beans.BeanUtils.copyProperties(achievement, response);
response.setId(achievement.getId());
if (achievement.getCreateTime() != null) {
response.setCreateTime(achievement.getCreateTime().format(DATE_TIME_FORMATTER));
}
if (achievement.getUpdateTime() != null) {
response.setUpdateTime(achievement.getUpdateTime().format(DATE_TIME_FORMATTER));
}
if (achievement.getUnlockedTime() != null) {
response.setUnlockedTime(achievement.getUnlockedTime().format(DATE_TIME_FORMATTER));
}
return response;
}
}
File diff suppressed because it is too large Load Diff
@@ -13,6 +13,7 @@ import com.emotion.exception.TokenException;
import com.emotion.service.AuthService;
import com.emotion.service.UserService;
import com.emotion.util.JwtUtil;
import com.emotion.util.TokenUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
@@ -22,6 +23,7 @@ import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
@@ -55,6 +57,9 @@ public class AuthServiceImpl implements AuthService {
@Autowired
private JwtUtil jwtUtil;
@Autowired
private TokenUtil tokenUtil;
private static final String CAPTCHA_PREFIX = "captcha:";
private static final String TOKEN_PREFIX = "token:";
private static final String REFRESH_TOKEN_PREFIX = "refresh_token:";
@@ -239,7 +244,8 @@ public class AuthServiceImpl implements AuthService {
}
@Override
public boolean logoutByToken(String token) {
public boolean logoutByToken(HttpServletRequest request) {
String token = tokenUtil.extractToken(request);
String userId = validateTokenAndGetUserId(token);
return logout(userId, token);
}
@@ -248,7 +254,7 @@ public class AuthServiceImpl implements AuthService {
* 验证令牌并获取用户ID
*/
private String validateTokenAndGetUserId(String token) {
if (!StringUtils.hasText(token)) {
if (!tokenUtil.isValidToken(token)) {
throw new TokenException("未提供访问令牌");
}
@@ -293,9 +299,15 @@ public class AuthServiceImpl implements AuthService {
return response;
}
@Override
public boolean validateToken(HttpServletRequest request) {
String token = tokenUtil.extractToken(request);
return validateToken(token);
}
@Override
public boolean validateToken(String token) {
if (!StringUtils.hasText(token)) {
if (!tokenUtil.isValidToken(token)) {
return false;
}
@@ -314,7 +326,7 @@ public class AuthServiceImpl implements AuthService {
@Override
public String getUserIdFromToken(String token) {
if (!StringUtils.hasText(token)) {
if (!tokenUtil.isValidToken(token)) {
return null;
}
@@ -336,7 +348,7 @@ public class AuthServiceImpl implements AuthService {
@Override
public String getUsernameFromToken(String token) {
if (!StringUtils.hasText(token)) {
if (!tokenUtil.isValidToken(token)) {
return null;
}
@@ -498,4 +510,4 @@ public class AuthServiceImpl implements AuthService {
User user = userService.getByPhone(phone);
return user != null;
}
}
}
@@ -1,18 +1,27 @@
package com.emotion.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.emotion.common.BasePageRequest;
import com.emotion.common.PageResult;
import com.emotion.dto.request.comment.CommentCreateRequest;
import com.emotion.dto.request.comment.CommentUpdateRequest;
import com.emotion.dto.request.comment.CommentPageRequest;
import com.emotion.dto.response.comment.CommentResponse;
import com.emotion.entity.Comment;
import com.emotion.mapper.CommentMapper;
import com.emotion.service.CommentService;
import com.emotion.util.SnowflakeIdGenerator;
import com.emotion.util.UserContextUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;
/**
* 评论服务实现类
@@ -23,219 +32,125 @@ import java.util.List;
@Service
public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> implements CommentService {
@Autowired
private SnowflakeIdGenerator snowflakeIdGenerator;
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@Override
public IPage<Comment> getPage(BasePageRequest request) {
public PageResult<CommentResponse> getPage(CommentPageRequest request) {
Page<Comment> page = new Page<>(request.getCurrent(), request.getSize());
LambdaQueryWrapper<Comment> wrapper = new LambdaQueryWrapper<>();
// 根据请求参数构建查询条件
if (StringUtils.hasText(request.getPostId())) {
wrapper.eq(Comment::getPostId, request.getPostId());
}
if (StringUtils.hasText(request.getUserId())) {
wrapper.eq(Comment::getUserId, request.getUserId());
}
if (StringUtils.hasText(request.getKeyword())) {
wrapper.like(Comment::getContent, request.getKeyword());
}
wrapper.eq(Comment::getIsDeleted, 0).orderByDesc(Comment::getCreateTime);
return this.page(page, wrapper);
page = this.page(page, wrapper);
return convertPageToPageResult(page);
}
@Override
public IPage<Comment> getPageByPostId(BasePageRequest request, String postId) {
Page<Comment> page = new Page<>(request.getCurrent(), request.getSize());
LambdaQueryWrapper<Comment> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Comment::getPostId, postId)
.eq(Comment::getIsDeleted, 0)
.orderByDesc(Comment::getCreateTime);
return this.page(page, wrapper);
public CommentResponse getById(String id) {
Comment comment = this.getBaseMapper().selectById(id);
if (comment == null) {
return null;
}
return convertToResponse(comment);
}
@Override
public IPage<Comment> getPageByUserId(BasePageRequest request, String userId) {
Page<Comment> page = new Page<>(request.getCurrent(), request.getSize());
LambdaQueryWrapper<Comment> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Comment::getUserId, userId)
.eq(Comment::getIsDeleted, 0)
.orderByDesc(Comment::getCreateTime);
return this.page(page, wrapper);
public CommentResponse create(CommentCreateRequest request) {
Comment comment = new Comment();
comment.setId(snowflakeIdGenerator.nextIdAsString()); // 使用雪花算法生成ID
comment.setPostId(request.getPostId());
// 从上下文中获取当前用户ID
String currentUserId = UserContextUtils.getCurrentUserId();
if (currentUserId != null) {
comment.setUserId(currentUserId);
} else if (request.getUserId() != null) {
// 如果上下文中没有用户ID,则使用请求中的用户ID(向后兼容)
comment.setUserId(request.getUserId());
} else {
throw new IllegalArgumentException("用户ID不能为空");
}
comment.setContent(request.getContent());
comment.setReplyToId(request.getReplyToId());
comment.setLikes(0);
this.save(comment);
return convertToResponse(comment);
}
@Override
public List<Comment> getByPostId(String postId) {
LambdaQueryWrapper<Comment> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Comment::getPostId, postId)
.eq(Comment::getIsDeleted, 0)
.orderByAsc(Comment::getCreateTime);
return this.list(wrapper);
public CommentResponse update(CommentUpdateRequest request) {
Comment comment = this.getBaseMapper().selectById(request.getId());
if (comment == null) {
return null;
}
// 只更新非空字段
if (StringUtils.hasText(request.getContent())) {
comment.setContent(request.getContent());
}
this.updateById(comment);
return convertToResponse(comment);
}
@Override
public List<Comment> getByUserId(String userId) {
LambdaQueryWrapper<Comment> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Comment::getUserId, userId)
.eq(Comment::getIsDeleted, 0)
.orderByDesc(Comment::getCreateTime);
return this.list(wrapper);
}
@Override
public List<Comment> getRepliesByCommentId(String replyToId) {
LambdaQueryWrapper<Comment> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Comment::getReplyToId, replyToId)
.eq(Comment::getIsDeleted, 0)
.orderByAsc(Comment::getCreateTime);
return this.list(wrapper);
}
@Override
public List<Comment> getTopLevelCommentsByPostId(String postId) {
LambdaQueryWrapper<Comment> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Comment::getPostId, postId)
.isNull(Comment::getReplyToId)
.eq(Comment::getIsDeleted, 0)
.orderByAsc(Comment::getCreateTime);
return this.list(wrapper);
}
@Override
public List<Comment> getByLikesRange(Integer minLikes, Integer maxLikes) {
LambdaQueryWrapper<Comment> wrapper = new LambdaQueryWrapper<>();
wrapper.between(Comment::getLikes, minLikes, maxLikes)
.eq(Comment::getIsDeleted, 0)
.orderByDesc(Comment::getLikes);
return this.list(wrapper);
}
@Override
public List<Comment> getByTimeRange(LocalDateTime startTime, LocalDateTime endTime) {
LambdaQueryWrapper<Comment> wrapper = new LambdaQueryWrapper<>();
wrapper.between(Comment::getCreateTime, startTime, endTime)
.eq(Comment::getIsDeleted, 0)
.orderByDesc(Comment::getCreateTime);
return this.list(wrapper);
}
@Override
public Long countByPostId(String postId) {
LambdaQueryWrapper<Comment> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Comment::getPostId, postId)
.eq(Comment::getIsDeleted, 0);
return this.count(wrapper);
}
@Override
public Long countByUserId(String userId) {
LambdaQueryWrapper<Comment> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Comment::getUserId, userId)
.eq(Comment::getIsDeleted, 0);
return this.count(wrapper);
}
@Override
public Long countRepliesByCommentId(String commentId) {
LambdaQueryWrapper<Comment> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Comment::getReplyToId, commentId)
.eq(Comment::getIsDeleted, 0);
return this.count(wrapper);
}
@Override
public Long countTopLevelCommentsByPostId(String postId) {
LambdaQueryWrapper<Comment> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Comment::getPostId, postId)
.isNull(Comment::getReplyToId)
.eq(Comment::getIsDeleted, 0);
return this.count(wrapper);
}
@Override
public List<Comment> getMostLikedCommentsByPostId(String postId, Integer limit) {
LambdaQueryWrapper<Comment> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Comment::getPostId, postId)
.eq(Comment::getIsDeleted, 0)
.orderByDesc(Comment::getLikes)
.last("LIMIT " + limit);
return this.list(wrapper);
}
@Override
public List<Comment> getLatestCommentsByPostId(String postId, Integer limit) {
LambdaQueryWrapper<Comment> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Comment::getPostId, postId)
.eq(Comment::getIsDeleted, 0)
.orderByDesc(Comment::getCreateTime)
.last("LIMIT " + limit);
return this.list(wrapper);
}
@Override
public List<Comment> getRecentByUserId(String userId, Integer limit) {
LambdaQueryWrapper<Comment> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Comment::getUserId, userId)
.eq(Comment::getIsDeleted, 0)
.orderByDesc(Comment::getCreateTime)
.last("LIMIT " + limit);
return this.list(wrapper);
}
@Override
public List<Comment> getPopularCommentsByPostId(String postId, Integer limit) {
// 这里需要自定义SQL查询,暂时返回最新评论
LambdaQueryWrapper<Comment> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Comment::getPostId, postId)
.eq(Comment::getIsDeleted, 0)
.orderByDesc(Comment::getCreateTime)
.last("LIMIT " + limit);
return this.list(wrapper);
}
@Override
public List<Comment> searchByKeyword(String keyword) {
LambdaQueryWrapper<Comment> wrapper = new LambdaQueryWrapper<>();
wrapper.like(Comment::getContent, keyword)
.eq(Comment::getIsDeleted, 0)
.orderByDesc(Comment::getCreateTime);
return this.list(wrapper);
}
@Override
public List<Comment> searchByPostIdAndKeyword(String postId, String keyword) {
LambdaQueryWrapper<Comment> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Comment::getPostId, postId)
.like(Comment::getContent, keyword)
.eq(Comment::getIsDeleted, 0)
.orderByDesc(Comment::getCreateTime);
return this.list(wrapper);
}
@Override
public List<Comment> getByPostIdAndUserId(String postId, String userId) {
LambdaQueryWrapper<Comment> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Comment::getPostId, postId)
.eq(Comment::getUserId, userId)
.eq(Comment::getIsDeleted, 0)
.orderByDesc(Comment::getCreateTime);
return this.list(wrapper);
}
@Override
public boolean updateLikes(String id, Integer increment) {
Comment comment = this.getById(id);
public boolean delete(String id) {
Comment comment = this.getBaseMapper().selectById(id);
if (comment == null) {
return false;
}
Integer newLikes = comment.getLikes() + increment;
comment.setLikes(newLikes);
// 逻辑删除
comment.setIsDeleted(1);
return this.updateById(comment);
}
@Override
public Comment createComment(String postId, String userId, String content, String replyToId) {
Comment comment = new Comment();
comment.setPostId(postId);
comment.setUserId(userId);
comment.setContent(content);
comment.setReplyToId(replyToId);
comment.setLikes(0);
/**
* 转换为响应对象
*/
private CommentResponse convertToResponse(Comment comment) {
CommentResponse response = new CommentResponse();
BeanUtils.copyProperties(comment, response);
response.setId(comment.getId());
if (comment.getCreateTime() != null) {
response.setCreateTime(comment.getCreateTime().format(DATE_TIME_FORMATTER));
}
if (comment.getUpdateTime() != null) {
response.setUpdateTime(comment.getUpdateTime().format(DATE_TIME_FORMATTER));
}
return response;
}
this.save(comment);
return comment;
/**
* 转换分页对象为PageResult对象
*/
private PageResult<CommentResponse> convertPageToPageResult(Page<Comment> page) {
PageResult<CommentResponse> pageResult = new PageResult<>();
pageResult.setCurrent(page.getCurrent());
pageResult.setSize(page.getSize());
pageResult.setTotal(page.getTotal());
pageResult.setPages(page.getPages());
pageResult.setRecords(page.getRecords().stream()
.map(this::convertToResponse)
.collect(Collectors.toList()));
return pageResult;
}
}
@@ -1,18 +1,26 @@
package com.emotion.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.emotion.common.BasePageRequest;
import com.emotion.common.PageResult;
import com.emotion.dto.request.community.CommunityPostCreateRequest;
import com.emotion.dto.request.community.CommunityPostUpdateRequest;
import com.emotion.dto.request.community.CommunityPostPageRequest;
import com.emotion.dto.response.community.CommunityPostResponse;
import com.emotion.entity.CommunityPost;
import com.emotion.mapper.CommunityPostMapper;
import com.emotion.service.CommunityPostService;
import com.emotion.util.SnowflakeIdGenerator;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;
/**
* 社区帖子服务实现类
@@ -23,296 +31,149 @@ import java.util.List;
@Service
public class CommunityPostServiceImpl extends ServiceImpl<CommunityPostMapper, CommunityPost> implements CommunityPostService {
@Autowired
private SnowflakeIdGenerator snowflakeIdGenerator;
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@Override
public IPage<CommunityPost> getPage(BasePageRequest request) {
public PageResult<CommunityPostResponse> getPage(CommunityPostPageRequest request) {
Page<CommunityPost> page = new Page<>(request.getCurrent(), request.getSize());
LambdaQueryWrapper<CommunityPost> wrapper = new LambdaQueryWrapper<>();
// 根据请求参数构建查询条件
if (StringUtils.hasText(request.getUserId())) {
wrapper.eq(CommunityPost::getUserId, request.getUserId());
}
if (StringUtils.hasText(request.getType())) {
wrapper.eq(CommunityPost::getType, request.getType());
}
if (StringUtils.hasText(request.getLocationId())) {
wrapper.eq(CommunityPost::getLocationId, request.getLocationId());
}
if (request.getPublicOnly() != null && request.getPublicOnly()) {
wrapper.eq(CommunityPost::getIsPrivate, 0);
}
if (StringUtils.hasText(request.getKeyword())) {
wrapper.and(w -> w.like(CommunityPost::getTitle, request.getKeyword())
.or().like(CommunityPost::getContent, request.getKeyword()));
}
wrapper.eq(CommunityPost::getIsDeleted, 0).orderByDesc(CommunityPost::getCreateTime);
return this.page(page, wrapper);
page = this.page(page, wrapper);
return convertPageToResponse(page);
}
@Override
public IPage<CommunityPost> getPublicPostsPage(BasePageRequest request) {
Page<CommunityPost> page = new Page<>(request.getCurrent(), request.getSize());
LambdaQueryWrapper<CommunityPost> wrapper = new LambdaQueryWrapper<>();
if (StringUtils.hasText(request.getKeyword())) {
wrapper.and(w -> w.like(CommunityPost::getTitle, request.getKeyword())
.or().like(CommunityPost::getContent, request.getKeyword()));
}
wrapper.eq(CommunityPost::getIsPrivate, 0)
.eq(CommunityPost::getIsDeleted, 0)
.orderByDesc(CommunityPost::getCreateTime);
return this.page(page, wrapper);
}
@Override
public IPage<CommunityPost> getPageByUserId(BasePageRequest request, String userId) {
Page<CommunityPost> page = new Page<>(request.getCurrent(), request.getSize());
LambdaQueryWrapper<CommunityPost> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(CommunityPost::getUserId, userId)
.eq(CommunityPost::getIsDeleted, 0)
.orderByDesc(CommunityPost::getCreateTime);
return this.page(page, wrapper);
}
@Override
public List<CommunityPost> getByLocationId(String locationId) {
LambdaQueryWrapper<CommunityPost> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(CommunityPost::getLocationId, locationId)
.eq(CommunityPost::getIsDeleted, 0)
.orderByDesc(CommunityPost::getCreateTime);
return this.list(wrapper);
}
@Override
public List<CommunityPost> getByType(String type) {
LambdaQueryWrapper<CommunityPost> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(CommunityPost::getType, type)
.eq(CommunityPost::getIsDeleted, 0)
.orderByDesc(CommunityPost::getCreateTime);
return this.list(wrapper);
}
@Override
public List<CommunityPost> getPrivatePostsByUserId(String userId) {
LambdaQueryWrapper<CommunityPost> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(CommunityPost::getUserId, userId)
.eq(CommunityPost::getIsPrivate, 1)
.eq(CommunityPost::getIsDeleted, 0)
.orderByDesc(CommunityPost::getCreateTime);
return this.list(wrapper);
}
@Override
public List<CommunityPost> getByLikesRange(Integer minLikes, Integer maxLikes) {
LambdaQueryWrapper<CommunityPost> wrapper = new LambdaQueryWrapper<>();
wrapper.between(CommunityPost::getLikes, minLikes, maxLikes)
.eq(CommunityPost::getIsDeleted, 0)
.orderByDesc(CommunityPost::getLikes);
return this.list(wrapper);
}
@Override
public List<CommunityPost> getByViewRange(Integer minViews, Integer maxViews) {
LambdaQueryWrapper<CommunityPost> wrapper = new LambdaQueryWrapper<>();
wrapper.between(CommunityPost::getViewCount, minViews, maxViews)
.eq(CommunityPost::getIsDeleted, 0)
.orderByDesc(CommunityPost::getViewCount);
return this.list(wrapper);
}
@Override
public List<CommunityPost> getByCommentRange(Integer minComments, Integer maxComments) {
LambdaQueryWrapper<CommunityPost> wrapper = new LambdaQueryWrapper<>();
wrapper.between(CommunityPost::getCommentCount, minComments, maxComments)
.eq(CommunityPost::getIsDeleted, 0)
.orderByDesc(CommunityPost::getCommentCount);
return this.list(wrapper);
}
@Override
public List<CommunityPost> getByTimeRange(LocalDateTime startTime, LocalDateTime endTime) {
LambdaQueryWrapper<CommunityPost> wrapper = new LambdaQueryWrapper<>();
wrapper.between(CommunityPost::getCreateTime, startTime, endTime)
.eq(CommunityPost::getIsDeleted, 0)
.orderByDesc(CommunityPost::getCreateTime);
return this.list(wrapper);
}
@Override
public Long countByUserId(String userId) {
LambdaQueryWrapper<CommunityPost> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(CommunityPost::getUserId, userId)
.eq(CommunityPost::getIsDeleted, 0);
return this.count(wrapper);
}
@Override
public Long countPublicPostsByUserId(String userId) {
LambdaQueryWrapper<CommunityPost> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(CommunityPost::getUserId, userId)
.eq(CommunityPost::getIsPrivate, 0)
.eq(CommunityPost::getIsDeleted, 0);
return this.count(wrapper);
}
@Override
public Long countPrivatePostsByUserId(String userId) {
LambdaQueryWrapper<CommunityPost> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(CommunityPost::getUserId, userId)
.eq(CommunityPost::getIsPrivate, 1)
.eq(CommunityPost::getIsDeleted, 0);
return this.count(wrapper);
}
@Override
public Long countByType(String type) {
LambdaQueryWrapper<CommunityPost> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(CommunityPost::getType, type)
.eq(CommunityPost::getIsDeleted, 0);
return this.count(wrapper);
}
@Override
public Long countByLocationId(String locationId) {
LambdaQueryWrapper<CommunityPost> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(CommunityPost::getLocationId, locationId)
.eq(CommunityPost::getIsDeleted, 0);
return this.count(wrapper);
}
@Override
public List<CommunityPost> getMostLikedPosts(Integer limit) {
LambdaQueryWrapper<CommunityPost> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(CommunityPost::getIsDeleted, 0)
.orderByDesc(CommunityPost::getLikes)
.last("LIMIT " + limit);
return this.list(wrapper);
}
@Override
public List<CommunityPost> getMostViewedPosts(Integer limit) {
LambdaQueryWrapper<CommunityPost> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(CommunityPost::getIsDeleted, 0)
.orderByDesc(CommunityPost::getViewCount)
.last("LIMIT " + limit);
return this.list(wrapper);
}
@Override
public List<CommunityPost> getLatestPosts(Integer limit) {
LambdaQueryWrapper<CommunityPost> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(CommunityPost::getIsDeleted, 0)
.orderByDesc(CommunityPost::getCreateTime)
.last("LIMIT " + limit);
return this.list(wrapper);
}
@Override
public List<CommunityPost> getPopularPosts(Integer limit) {
// 这里需要自定义SQL查询,暂时返回最新帖子
LambdaQueryWrapper<CommunityPost> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(CommunityPost::getIsDeleted, 0)
.orderByDesc(CommunityPost::getCreateTime)
.last("LIMIT " + limit);
return this.list(wrapper);
}
@Override
public List<CommunityPost> getByTag(String tag) {
LambdaQueryWrapper<CommunityPost> wrapper = new LambdaQueryWrapper<>();
wrapper.like(CommunityPost::getTags, tag)
.eq(CommunityPost::getIsDeleted, 0)
.orderByDesc(CommunityPost::getCreateTime);
return this.list(wrapper);
}
@Override
public List<CommunityPost> searchByKeyword(String keyword) {
LambdaQueryWrapper<CommunityPost> wrapper = new LambdaQueryWrapper<>();
wrapper.and(w -> w.like(CommunityPost::getTitle, keyword)
.or().like(CommunityPost::getContent, keyword))
.eq(CommunityPost::getIsDeleted, 0)
.orderByDesc(CommunityPost::getCreateTime);
return this.list(wrapper);
}
@Override
public List<CommunityPost> getRecentByUserId(String userId, Integer limit) {
LambdaQueryWrapper<CommunityPost> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(CommunityPost::getUserId, userId)
.eq(CommunityPost::getIsDeleted, 0)
.orderByDesc(CommunityPost::getCreateTime)
.last("LIMIT " + limit);
return this.list(wrapper);
}
@Override
public boolean updateLikes(String id, Integer increment) {
CommunityPost post = this.getById(id);
public CommunityPostResponse getById(String id) {
CommunityPost post = this.getBaseMapper().selectById(id);
if (post == null) {
return false;
return null;
}
// 增加浏览数
Integer viewCount = post.getViewCount() == null ? 1 : post.getViewCount() + 1;
post.setViewCount(viewCount);
this.updateById(post);
Integer newLikes = post.getLikes() + increment;
post.setLikes(newLikes);
return this.updateById(post);
return convertToResponse(post);
}
@Override
public boolean incrementViewCount(String id) {
CommunityPost post = this.getById(id);
if (post == null) {
return false;
}
Integer newViewCount = post.getViewCount() + 1;
post.setViewCount(newViewCount);
return this.updateById(post);
}
@Override
public boolean updateCommentCount(String id, Integer increment) {
CommunityPost post = this.getById(id);
if (post == null) {
return false;
}
Integer newCommentCount = post.getCommentCount() + increment;
post.setCommentCount(newCommentCount);
return this.updateById(post);
}
@Override
public boolean updatePrivacyStatus(String id, Integer isPrivate) {
public CommunityPostResponse create(CommunityPostCreateRequest request) {
CommunityPost post = new CommunityPost();
post.setId(id);
post.setIsPrivate(isPrivate);
return this.updateById(post);
}
@Override
public List<CommunityPost> getRecommendedPosts(String type, String locationId, Integer limit) {
LambdaQueryWrapper<CommunityPost> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(CommunityPost::getIsDeleted, 0);
if (StringUtils.hasText(type)) {
wrapper.eq(CommunityPost::getType, type);
}
if (StringUtils.hasText(locationId)) {
wrapper.eq(CommunityPost::getLocationId, locationId);
}
wrapper.orderByDesc(CommunityPost::getCreateTime)
.last("LIMIT " + limit);
return this.list(wrapper);
}
@Override
public CommunityPost createPost(String userId, String title, String content, String type,
String locationId, String tags, Integer isPrivate) {
CommunityPost post = new CommunityPost();
post.setUserId(userId);
post.setTitle(title);
post.setContent(content);
post.setType(type);
post.setLocationId(locationId);
post.setTags(tags);
post.setIsPrivate(isPrivate);
post.setId(snowflakeIdGenerator.nextIdAsString()); // 使用雪花算法生成ID
post.setUserId(request.getUserId());
post.setTitle(request.getTitle());
post.setContent(request.getContent());
post.setType(request.getType());
post.setLocationId(request.getLocationId());
post.setTags(request.getTags());
post.setIsPrivate(request.getIsPrivate() != null ? request.getIsPrivate() : 0); // 默认公开
post.setLikes(0);
post.setViewCount(0);
post.setCommentCount(0);
this.save(post);
return post;
return convertToResponse(post);
}
@Override
public CommunityPostResponse update(CommunityPostUpdateRequest request) {
CommunityPost post = this.getBaseMapper().selectById(request.getId());
if (post == null) {
return null;
}
// 只更新非空字段
if (request.getTitle() != null) {
post.setTitle(request.getTitle());
}
if (request.getContent() != null) {
post.setContent(request.getContent());
}
if (request.getType() != null) {
post.setType(request.getType());
}
if (request.getLocationId() != null) {
post.setLocationId(request.getLocationId());
}
if (request.getTags() != null) {
post.setTags(request.getTags());
}
if (request.getIsPrivate() != null) {
post.setIsPrivate(request.getIsPrivate());
}
this.updateById(post);
return convertToResponse(post);
}
@Override
public boolean delete(String id) {
CommunityPost post = this.getBaseMapper().selectById(id);
if (post == null) {
return false;
}
// 逻辑删除
post.setIsDeleted(1);
return this.updateById(post);
}
/**
* 转换为响应对象
*/
private CommunityPostResponse convertToResponse(CommunityPost post) {
CommunityPostResponse response = new CommunityPostResponse();
BeanUtils.copyProperties(post, response);
response.setId(post.getId());
if (post.getCreateTime() != null) {
response.setCreateTime(post.getCreateTime().format(DATE_TIME_FORMATTER));
}
if (post.getUpdateTime() != null) {
response.setUpdateTime(post.getUpdateTime().format(DATE_TIME_FORMATTER));
}
return response;
}
/**
* 转换分页对象为响应对象
*/
private PageResult<CommunityPostResponse> convertPageToResponse(Page<CommunityPost> page) {
PageResult<CommunityPostResponse> responsePage = new PageResult<>();
responsePage.setCurrent(page.getCurrent());
responsePage.setSize(page.getSize());
responsePage.setTotal(page.getTotal());
responsePage.setPages(page.getPages());
responsePage.setRecords(
page.getRecords().stream()
.map(this::convertToResponse)
.collect(Collectors.toList()));
return responsePage;
}
}
@@ -4,15 +4,25 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.emotion.common.BasePageRequest;
import com.emotion.common.PageResult;
import com.emotion.dto.request.ConversationCreateRequest;
import com.emotion.dto.request.ConversationPageRequest;
import com.emotion.dto.response.ConversationResponse;
import com.emotion.entity.Conversation;
import com.emotion.mapper.ConversationMapper;
import com.emotion.service.ConversationService;
import com.emotion.util.SnowflakeIdGenerator;
import com.emotion.util.UserContextUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;
/**
* 会话服务实现类
@@ -23,11 +33,29 @@ import java.util.List;
@Service
public class ConversationServiceImpl extends ServiceImpl<ConversationMapper, Conversation> implements ConversationService {
@Autowired
private SnowflakeIdGenerator snowflakeIdGenerator;
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@Override
public IPage<Conversation> getPage(BasePageRequest request) {
public IPage<Conversation> getPage(ConversationPageRequest request) {
Page<Conversation> page = new Page<>(request.getCurrent(), request.getSize());
LambdaQueryWrapper<Conversation> wrapper = new LambdaQueryWrapper<>();
// 根据请求参数构建查询条件
if (StringUtils.hasText(request.getUserId())) {
wrapper.eq(Conversation::getUserId, request.getUserId());
}
if (StringUtils.hasText(request.getStatus())) {
wrapper.eq(Conversation::getConversationStatus, request.getStatus());
}
if (StringUtils.hasText(request.getType())) {
wrapper.eq(Conversation::getType, request.getType());
}
if (StringUtils.hasText(request.getKeyword())) {
wrapper.and(w -> w.like(Conversation::getTitle, request.getKeyword())
.or().like(Conversation::getSummary, request.getKeyword()));
@@ -38,10 +66,16 @@ public class ConversationServiceImpl extends ServiceImpl<ConversationMapper, Con
}
@Override
public IPage<Conversation> getPageByUserId(BasePageRequest request, String userId) {
public IPage<Conversation> getPageByUserId(ConversationPageRequest request) {
Page<Conversation> page = new Page<>(request.getCurrent(), request.getSize());
LambdaQueryWrapper<Conversation> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Conversation::getUserId, userId)
// 必须提供userId参数
if (!StringUtils.hasText(request.getUserId())) {
throw new IllegalArgumentException("userId不能为空");
}
wrapper.eq(Conversation::getUserId, request.getUserId())
.eq(Conversation::getIsDeleted, 0)
.orderByDesc(Conversation::getCreateTime);
return this.page(page, wrapper);
@@ -148,6 +182,7 @@ public class ConversationServiceImpl extends ServiceImpl<ConversationMapper, Con
@Override
public Conversation createConversation(String userId, String title, String cozeConversationId) {
Conversation conversation = new Conversation();
conversation.setId(snowflakeIdGenerator.nextIdAsString()); // 使用雪花算法生成ID
conversation.setUserId(userId);
conversation.setTitle(title);
conversation.setCozeConversationId(cozeConversationId);
@@ -172,4 +207,157 @@ public class ConversationServiceImpl extends ServiceImpl<ConversationMapper, Con
conversation.setEndTime(LocalDateTime.now());
return this.updateById(conversation);
}
@Override
public PageResult<ConversationResponse> getPageWithResponse(ConversationPageRequest request) {
IPage<Conversation> page = this.getPage(request);
return convertPageToResponse(page);
}
@Override
public PageResult<ConversationResponse> getPageByUserIdWithResponse(ConversationPageRequest request) {
IPage<Conversation> page = this.getPageByUserId(request);
return convertPageToResponse(page);
}
@Override
public ConversationResponse getConversationResponseById(String id) {
Conversation conversation = this.getById(id);
if (conversation == null) {
return null;
}
return convertToResponse(conversation);
}
@Override
public List<ConversationResponse> getByUserIdWithResponse(String userId) {
List<Conversation> conversations = this.getByUserId(userId);
return conversations.stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
}
@Override
public List<ConversationResponse> getActiveConversationsWithResponse() {
// 实现获取活跃对话的逻辑
LambdaQueryWrapper<Conversation> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Conversation::getConversationStatus, "active")
.eq(Conversation::getIsDeleted, 0)
.orderByDesc(Conversation::getLastActiveTime);
List<Conversation> conversations = this.list(wrapper);
return conversations.stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
}
@Override
public List<ConversationResponse> getArchivedConversationsWithResponse() {
// 实现获取归档对话的逻辑
LambdaQueryWrapper<Conversation> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Conversation::getConversationStatus, "archived")
.eq(Conversation::getIsDeleted, 0)
.orderByDesc(Conversation::getCreateTime);
List<Conversation> conversations = this.list(wrapper);
return conversations.stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
}
@Override
public boolean archiveConversation(String id) {
Conversation conversation = new Conversation();
conversation.setId(id);
conversation.setConversationStatus("archived");
return this.updateById(conversation);
}
@Override
public boolean activateConversation(String id) {
Conversation conversation = new Conversation();
conversation.setId(id);
conversation.setConversationStatus("active");
return this.updateById(conversation);
}
@Override
public ConversationResponse createConversationWithResponse(ConversationCreateRequest request,
HttpServletRequest httpRequest) {
// 获取客户端IP地址
String clientIp = UserContextUtils.getClientIpAddress(httpRequest);
Conversation conversation = this.createConversation(
request.getUserId(),
request.getTitle(),
null // cozeConversationId
);
// 设置客户端IP
conversation.setClientIp(clientIp);
this.updateById(conversation);
return convertToResponse(conversation);
}
@Override
public ConversationResponse updateConversationWithResponse(ConversationCreateRequest request) {
Conversation conversation = this.getById(request.getId()); // 修复:使用ID而不是userId
if (conversation == null) {
return null;
}
// 更新字段
if (request.getTitle() != null) {
conversation.setTitle(request.getTitle());
}
if (request.getType() != null) {
conversation.setType(request.getType());
}
this.updateById(conversation);
return convertToResponse(conversation);
}
@Override
public boolean updateConversationStatus(String id, String status) {
Conversation conversation = new Conversation();
conversation.setId(id);
conversation.setConversationStatus(status);
return this.updateById(conversation);
}
/**
* 转换为响应对象
*/
private ConversationResponse convertToResponse(Conversation conversation) {
ConversationResponse response = new ConversationResponse();
BeanUtils.copyProperties(conversation, response);
response.setId(conversation.getId());
response.setStatus(conversation.getConversationStatus());
if (conversation.getCreateTime() != null) {
response.setCreateTime(conversation.getCreateTime().format(DATE_TIME_FORMATTER));
}
if (conversation.getUpdateTime() != null) {
response.setUpdateTime(conversation.getUpdateTime().format(DATE_TIME_FORMATTER));
}
if (conversation.getLastActiveTime() != null) {
response.setLastMessageTime(conversation.getLastActiveTime().format(DATE_TIME_FORMATTER));
}
return response;
}
/**
* 转换分页对象为响应对象
*/
private PageResult<ConversationResponse> convertPageToResponse(IPage<Conversation> page) {
PageResult<ConversationResponse> responsePage = new PageResult<>();
responsePage.setCurrent(page.getCurrent());
responsePage.setSize(page.getSize());
responsePage.setTotal(page.getTotal());
responsePage.setPages(page.getPages());
responsePage.setRecords(
page.getRecords().stream()
.map(this::convertToResponse)
.collect(Collectors.toList()));
return responsePage;
}
}
@@ -1,20 +1,27 @@
package com.emotion.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.emotion.common.BasePageRequest;
import com.emotion.common.PageResult;
import com.emotion.dto.request.coze.CozeApiCallPageRequest;
import com.emotion.dto.request.coze.CozeApiCallCreateRequest;
import com.emotion.dto.request.coze.CozeApiCallUpdateRequest;
import com.emotion.dto.response.coze.CozeApiCallResponse;
import com.emotion.entity.CozeApiCall;
import com.emotion.mapper.CozeApiCallMapper;
import com.emotion.service.CozeApiCallService;
import com.emotion.util.SnowflakeIdGenerator;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;
/**
* Coze API调用记录服务实现类
@@ -25,15 +32,46 @@ import java.util.List;
@Service
public class CozeApiCallServiceImpl extends ServiceImpl<CozeApiCallMapper, CozeApiCall> implements CozeApiCallService {
@Autowired
private SnowflakeIdGenerator snowflakeIdGenerator;
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@Override
public IPage<CozeApiCall> getPage(BasePageRequest request) {
public PageResult<CozeApiCallResponse> getPage(CozeApiCallPageRequest request) {
Page<CozeApiCall> page = new Page<>(request.getCurrent(), request.getSize());
LambdaQueryWrapper<CozeApiCall> wrapper = new LambdaQueryWrapper<>();
// 根据请求参数构建查询条件
if (StringUtils.hasText(request.getConversationId())) {
wrapper.eq(CozeApiCall::getConversationId, request.getConversationId());
}
if (StringUtils.hasText(request.getUserId())) {
wrapper.eq(CozeApiCall::getUserId, request.getUserId());
}
if (StringUtils.hasText(request.getBotId())) {
wrapper.eq(CozeApiCall::getBotId, request.getBotId());
}
if (StringUtils.hasText(request.getStatus())) {
wrapper.eq(CozeApiCall::getStatus, request.getStatus());
}
if (StringUtils.hasText(request.getRequestType())) {
wrapper.eq(CozeApiCall::getRequestType, request.getRequestType());
}
if (StringUtils.hasText(request.getTraceId())) {
wrapper.eq(CozeApiCall::getTraceId, request.getTraceId());
}
// 关键词搜索
if (StringUtils.hasText(request.getKeyword())) {
wrapper.like(CozeApiCall::getRequestUrl, request.getKeyword())
.or().like(CozeApiCall::getAiReply, request.getKeyword());
wrapper.and(w -> w.like(CozeApiCall::getRequestUrl, request.getKeyword())
.or().like(CozeApiCall::getAiReply, request.getKeyword())
.or().like(CozeApiCall::getUserMessage, request.getKeyword()));
}
wrapper.eq(CozeApiCall::getIsDeleted, 0);
@@ -49,77 +87,193 @@ public class CozeApiCallServiceImpl extends ServiceImpl<CozeApiCallMapper, CozeA
wrapper.orderByDesc(CozeApiCall::getStartTime);
}
return this.page(page, wrapper);
page = this.page(page, wrapper);
return convertPageToPageResult(page);
}
@Override
public IPage<CozeApiCall> getPageByConversationId(BasePageRequest request, String conversationId) {
Page<CozeApiCall> page = new Page<>(request.getCurrent(), request.getSize());
LambdaQueryWrapper<CozeApiCall> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(CozeApiCall::getConversationId, conversationId)
.eq(CozeApiCall::getIsDeleted, 0);
public CozeApiCallResponse getById(String id) {
CozeApiCall apiCall = this.getBaseMapper().selectById(id);
if (apiCall == null || apiCall.getIsDeleted() == 1) {
return null;
}
return convertToResponse(apiCall);
}
// 关键词搜索
if (StringUtils.hasText(request.getKeyword())) {
wrapper.like(CozeApiCall::getRequestUrl, request.getKeyword())
.or().like(CozeApiCall::getAiReply, request.getKeyword());
@Override
public CozeApiCallResponse create(CozeApiCallCreateRequest request) {
CozeApiCall apiCall = new CozeApiCall();
apiCall.setId(snowflakeIdGenerator.nextIdAsString()); // 使用雪花算法生成ID
// 复制属性
apiCall.setConversationId(request.getConversationId());
apiCall.setMessageId(request.getMessageId());
apiCall.setCozeChatId(request.getCozeChatId());
apiCall.setCozeConversationId(request.getCozeConversationId());
apiCall.setBotId(request.getBotId());
apiCall.setWorkflowId(request.getWorkflowId());
apiCall.setUserId(request.getUserId());
apiCall.setRequestType(request.getRequestType());
apiCall.setRequestUrl(request.getRequestUrl());
apiCall.setRequestBody(request.getRequestBody());
apiCall.setRequestHeaders(request.getRequestHeaders());
apiCall.setUserMessage(request.getUserMessage());
apiCall.setUserMessageType(request.getUserMessageType());
apiCall.setAiReply(request.getAiReply());
apiCall.setAiReplyType(request.getAiReplyType());
apiCall.setResponseStatus(request.getResponseStatus());
apiCall.setResponseBody(request.getResponseBody());
apiCall.setResponseHeaders(request.getResponseHeaders());
apiCall.setPollCount(request.getPollCount());
apiCall.setFinalStatus(request.getFinalStatus());
apiCall.setStatus(request.getStatus());
apiCall.setDurationMs(request.getDurationMs());
apiCall.setPromptTokens(request.getPromptTokens());
apiCall.setCompletionTokens(request.getCompletionTokens());
apiCall.setTotalTokens(request.getTotalTokens());
apiCall.setCost(request.getCost());
apiCall.setFunctionCalls(request.getFunctionCalls());
apiCall.setFunctionResults(request.getFunctionResults());
apiCall.setErrorCode(request.getErrorCode());
apiCall.setErrorMessage(request.getErrorMessage());
apiCall.setClientIp(request.getClientIp());
apiCall.setUserAgent(request.getUserAgent());
apiCall.setSessionId(request.getSessionId());
apiCall.setTraceId(request.getTraceId());
apiCall.setMetadata(request.getMetadata());
this.save(apiCall);
return convertToResponse(apiCall);
}
@Override
public CozeApiCallResponse update(CozeApiCallUpdateRequest request) {
CozeApiCall apiCall = this.getBaseMapper().selectById(request.getId());
if (apiCall == null || apiCall.getIsDeleted() == 1) {
return null;
}
wrapper.orderByDesc(CozeApiCall::getStartTime);
return this.page(page, wrapper);
}
@Override
public IPage<CozeApiCall> getPageByUserId(BasePageRequest request, String userId) {
Page<CozeApiCall> page = new Page<>(request.getCurrent(), request.getSize());
LambdaQueryWrapper<CozeApiCall> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(CozeApiCall::getUserId, userId)
.eq(CozeApiCall::getIsDeleted, 0);
// 关键词搜索
if (StringUtils.hasText(request.getKeyword())) {
wrapper.like(CozeApiCall::getRequestUrl, request.getKeyword())
.or().like(CozeApiCall::getAiReply, request.getKeyword());
// 只更新非空字段
if (request.getConversationId() != null) {
apiCall.setConversationId(request.getConversationId());
}
if (request.getMessageId() != null) {
apiCall.setMessageId(request.getMessageId());
}
if (request.getCozeChatId() != null) {
apiCall.setCozeChatId(request.getCozeChatId());
}
if (request.getCozeConversationId() != null) {
apiCall.setCozeConversationId(request.getCozeConversationId());
}
if (request.getBotId() != null) {
apiCall.setBotId(request.getBotId());
}
if (request.getWorkflowId() != null) {
apiCall.setWorkflowId(request.getWorkflowId());
}
if (request.getUserId() != null) {
apiCall.setUserId(request.getUserId());
}
if (request.getRequestType() != null) {
apiCall.setRequestType(request.getRequestType());
}
if (request.getRequestUrl() != null) {
apiCall.setRequestUrl(request.getRequestUrl());
}
if (request.getRequestBody() != null) {
apiCall.setRequestBody(request.getRequestBody());
}
if (request.getRequestHeaders() != null) {
apiCall.setRequestHeaders(request.getRequestHeaders());
}
if (request.getUserMessage() != null) {
apiCall.setUserMessage(request.getUserMessage());
}
if (request.getUserMessageType() != null) {
apiCall.setUserMessageType(request.getUserMessageType());
}
if (request.getAiReply() != null) {
apiCall.setAiReply(request.getAiReply());
}
if (request.getAiReplyType() != null) {
apiCall.setAiReplyType(request.getAiReplyType());
}
if (request.getResponseStatus() != null) {
apiCall.setResponseStatus(request.getResponseStatus());
}
if (request.getResponseBody() != null) {
apiCall.setResponseBody(request.getResponseBody());
}
if (request.getResponseHeaders() != null) {
apiCall.setResponseHeaders(request.getResponseHeaders());
}
if (request.getPollCount() != null) {
apiCall.setPollCount(request.getPollCount());
}
if (request.getFinalStatus() != null) {
apiCall.setFinalStatus(request.getFinalStatus());
}
if (request.getStatus() != null) {
apiCall.setStatus(request.getStatus());
}
if (request.getDurationMs() != null) {
apiCall.setDurationMs(request.getDurationMs());
}
if (request.getPromptTokens() != null) {
apiCall.setPromptTokens(request.getPromptTokens());
}
if (request.getCompletionTokens() != null) {
apiCall.setCompletionTokens(request.getCompletionTokens());
}
if (request.getTotalTokens() != null) {
apiCall.setTotalTokens(request.getTotalTokens());
}
if (request.getCost() != null) {
apiCall.setCost(request.getCost());
}
if (request.getFunctionCalls() != null) {
apiCall.setFunctionCalls(request.getFunctionCalls());
}
if (request.getFunctionResults() != null) {
apiCall.setFunctionResults(request.getFunctionResults());
}
if (request.getErrorCode() != null) {
apiCall.setErrorCode(request.getErrorCode());
}
if (request.getErrorMessage() != null) {
apiCall.setErrorMessage(request.getErrorMessage());
}
if (request.getClientIp() != null) {
apiCall.setClientIp(request.getClientIp());
}
if (request.getUserAgent() != null) {
apiCall.setUserAgent(request.getUserAgent());
}
if (request.getSessionId() != null) {
apiCall.setSessionId(request.getSessionId());
}
if (request.getTraceId() != null) {
apiCall.setTraceId(request.getTraceId());
}
if (request.getMetadata() != null) {
apiCall.setMetadata(request.getMetadata());
}
wrapper.orderByDesc(CozeApiCall::getStartTime);
return this.page(page, wrapper);
this.updateById(apiCall);
return convertToResponse(apiCall);
}
@Override
public List<CozeApiCall> getByBotId(String botId) {
LambdaQueryWrapper<CozeApiCall> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(CozeApiCall::getBotId, botId)
.eq(CozeApiCall::getIsDeleted, 0)
.orderByDesc(CozeApiCall::getStartTime);
return this.list(wrapper);
}
public boolean delete(String id) {
CozeApiCall apiCall = this.getBaseMapper().selectById(id);
if (apiCall == null) {
return false;
}
@Override
public List<CozeApiCall> getByStatus(String status) {
LambdaQueryWrapper<CozeApiCall> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(CozeApiCall::getStatus, status)
.eq(CozeApiCall::getIsDeleted, 0)
.orderByDesc(CozeApiCall::getStartTime);
return this.list(wrapper);
}
@Override
public List<CozeApiCall> getByRequestType(String requestType) {
LambdaQueryWrapper<CozeApiCall> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(CozeApiCall::getRequestType, requestType)
.eq(CozeApiCall::getIsDeleted, 0)
.orderByDesc(CozeApiCall::getStartTime);
return this.list(wrapper);
}
@Override
public List<CozeApiCall> getByTimeRange(LocalDateTime startTime, LocalDateTime endTime) {
LambdaQueryWrapper<CozeApiCall> wrapper = new LambdaQueryWrapper<>();
wrapper.between(CozeApiCall::getStartTime, startTime, endTime)
.eq(CozeApiCall::getIsDeleted, 0)
.orderByDesc(CozeApiCall::getStartTime);
return this.list(wrapper);
// 逻辑删除
apiCall.setIsDeleted(1);
return this.updateById(apiCall);
}
@Override
@@ -167,87 +321,46 @@ public class CozeApiCallServiceImpl extends ServiceImpl<CozeApiCallMapper, CozeA
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
@Override
public List<CozeApiCall> getFailedCalls() {
LambdaQueryWrapper<CozeApiCall> wrapper = new LambdaQueryWrapper<>();
wrapper.and(w -> w.eq(CozeApiCall::getStatus, "failed").or().eq(CozeApiCall::getFinalStatus, "failed"))
.eq(CozeApiCall::getIsDeleted, 0)
.orderByDesc(CozeApiCall::getStartTime);
return this.list(wrapper);
/**
* 转换为响应对象
*/
private CozeApiCallResponse convertToResponse(CozeApiCall apiCall) {
CozeApiCallResponse response = new CozeApiCallResponse();
BeanUtils.copyProperties(apiCall, response);
response.setId(apiCall.getId());
if (apiCall.getCreateTime() != null) {
response.setCreateTime(apiCall.getCreateTime().format(DATE_TIME_FORMATTER));
}
if (apiCall.getUpdateTime() != null) {
response.setUpdateTime(apiCall.getUpdateTime().format(DATE_TIME_FORMATTER));
}
if (apiCall.getStartTime() != null) {
response.setStartTime(apiCall.getStartTime().format(DATE_TIME_FORMATTER));
}
if (apiCall.getEndTime() != null) {
response.setEndTime(apiCall.getEndTime().format(DATE_TIME_FORMATTER));
}
if (apiCall.getPollStartTime() != null) {
response.setPollStartTime(apiCall.getPollStartTime().format(DATE_TIME_FORMATTER));
}
if (apiCall.getPollEndTime() != null) {
response.setPollEndTime(apiCall.getPollEndTime().format(DATE_TIME_FORMATTER));
}
return response;
}
@Override
public List<CozeApiCall> getTimeoutCalls() {
LambdaQueryWrapper<CozeApiCall> wrapper = new LambdaQueryWrapper<>();
wrapper.and(w -> w.eq(CozeApiCall::getStatus, "timeout").or().eq(CozeApiCall::getFinalStatus, "timeout"))
.eq(CozeApiCall::getIsDeleted, 0)
.orderByDesc(CozeApiCall::getStartTime);
return this.list(wrapper);
/**
* 转换分页对象为PageResult对象
*/
private PageResult<CozeApiCallResponse> convertPageToPageResult(Page<CozeApiCall> page) {
PageResult<CozeApiCallResponse> pageResult = new PageResult<>();
pageResult.setCurrent(page.getCurrent());
pageResult.setSize(page.getSize());
pageResult.setTotal(page.getTotal());
pageResult.setPages(page.getPages());
pageResult.setRecords(page.getRecords().stream()
.map(this::convertToResponse)
.collect(Collectors.toList()));
return pageResult;
}
@Override
public CozeApiCall getByTraceId(String traceId) {
LambdaQueryWrapper<CozeApiCall> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(CozeApiCall::getTraceId, traceId)
.eq(CozeApiCall::getIsDeleted, 0);
return this.getOne(wrapper);
}
@Override
public List<CozeApiCall> getByConversationIdAndRequestType(String conversationId, String requestType) {
LambdaQueryWrapper<CozeApiCall> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(CozeApiCall::getConversationId, conversationId)
.eq(CozeApiCall::getRequestType, requestType)
.eq(CozeApiCall::getIsDeleted, 0)
.orderByDesc(CozeApiCall::getStartTime);
return this.list(wrapper);
}
@Override
public boolean updateStatus(String id, String status, String finalStatus, LocalDateTime endTime) {
LambdaUpdateWrapper<CozeApiCall> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(CozeApiCall::getId, id)
.set(CozeApiCall::getStatus, status)
.set(CozeApiCall::getFinalStatus, finalStatus)
.set(CozeApiCall::getEndTime, endTime)
.set(CozeApiCall::getUpdateTime, LocalDateTime.now());
return this.update(wrapper);
}
@Override
public boolean updateResult(String id, Integer responseStatus, String responseBody, String aiReply,
Integer totalTokens, BigDecimal cost, String status, String finalStatus,
LocalDateTime endTime) {
LambdaUpdateWrapper<CozeApiCall> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(CozeApiCall::getId, id)
.set(CozeApiCall::getResponseStatus, responseStatus)
.set(CozeApiCall::getResponseBody, responseBody)
.set(CozeApiCall::getAiReply, aiReply)
.set(CozeApiCall::getTotalTokens, totalTokens)
.set(CozeApiCall::getCost, cost)
.set(CozeApiCall::getStatus, status)
.set(CozeApiCall::getFinalStatus, finalStatus)
.set(CozeApiCall::getEndTime, endTime)
.set(CozeApiCall::getUpdateTime, LocalDateTime.now());
return this.update(wrapper);
}
@Override
public CozeApiCall createApiCall(String conversationId, String messageId, String userId,
String requestType, String requestUrl, String requestBody) {
CozeApiCall apiCall = CozeApiCall.builder()
.conversationId(conversationId)
.messageId(messageId)
.userId(userId)
.requestType(requestType)
.requestUrl(requestUrl)
.requestBody(requestBody)
.status("pending")
.startTime(LocalDateTime.now())
.createBy(userId) // 设置创建人为当前用户
.updateBy(userId) // 设置更新人为当前用户
.build();
this.save(apiCall);
return apiCall;
}
}
}
@@ -5,18 +5,24 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.emotion.common.BasePageRequest;
import com.emotion.common.PageResult;
import com.emotion.dto.request.DiaryCommentCreateRequest;
import com.emotion.dto.request.DiaryCommentPageRequest;
import com.emotion.dto.response.DiaryCommentResponse;
import com.emotion.entity.DiaryComment;
import com.emotion.mapper.DiaryCommentMapper;
import com.emotion.service.DiaryCommentService;
import com.emotion.util.SnowflakeIdGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;
@@ -29,207 +35,105 @@ import java.util.stream.Collectors;
@Service
public class DiaryCommentServiceImpl extends ServiceImpl<DiaryCommentMapper, DiaryComment> implements DiaryCommentService {
@Autowired
private SnowflakeIdGenerator snowflakeIdGenerator;
@Autowired
private ObjectMapper objectMapper;
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@Override
public IPage<DiaryComment> getPage(BasePageRequest request) {
public PageResult<DiaryCommentResponse> getPageWithResponse(DiaryCommentPageRequest request) {
Page<DiaryComment> page = new Page<>(request.getCurrent(), request.getSize());
LambdaQueryWrapper<DiaryComment> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(DiaryComment::getIsDeleted, 0)
.orderByDesc(DiaryComment::getIsTop)
// 基础查询条件
wrapper.eq(DiaryComment::getIsDeleted, 0);
// 根据请求参数添加查询条件
if (StringUtils.hasText(request.getDiaryId())) {
wrapper.eq(DiaryComment::getDiaryId, request.getDiaryId());
}
if (StringUtils.hasText(request.getUserId())) {
wrapper.eq(DiaryComment::getUserId, request.getUserId());
}
if (StringUtils.hasText(request.getCommentType())) {
wrapper.eq(DiaryComment::getCommentType, request.getCommentType());
}
if (request.getTopLevelOnly() != null && request.getTopLevelOnly()) {
wrapper.isNull(DiaryComment::getParentCommentId);
}
// 排序
wrapper.orderByDesc(DiaryComment::getIsTop)
.orderByDesc(DiaryComment::getPublishTime);
return this.page(page, wrapper);
IPage<DiaryComment> resultPage = this.page(page, wrapper);
return convertPageToResponse(resultPage);
}
@Override
public IPage<DiaryComment> getPageByDiaryId(String diaryId, BasePageRequest request) {
Page<DiaryComment> page = new Page<>(request.getCurrent(), request.getSize());
LambdaQueryWrapper<DiaryComment> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(DiaryComment::getDiaryId, diaryId)
.eq(DiaryComment::getIsDeleted, 0)
.orderByDesc(DiaryComment::getIsTop)
.orderByDesc(DiaryComment::getPublishTime);
return this.page(page, wrapper);
public DiaryCommentResponse getCommentResponseById(String id) {
DiaryComment comment = this.getById(id);
if (comment == null) {
return null;
}
return convertToResponse(comment);
}
@Override
public IPage<DiaryComment> getPageByUserId(String userId, BasePageRequest request) {
Page<DiaryComment> page = new Page<>(request.getCurrent(), request.getSize());
LambdaQueryWrapper<DiaryComment> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(DiaryComment::getUserId, userId)
.eq(DiaryComment::getIsDeleted, 0)
.orderByDesc(DiaryComment::getPublishTime);
return this.page(page, wrapper);
public List<DiaryCommentResponse> getCommentTreeWithResponse(String diaryId) {
List<DiaryComment> comments = this.getCommentTree(diaryId);
return comments.stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
}
@Override
public List<DiaryComment> getRepliesByParentId(String parentCommentId) {
LambdaQueryWrapper<DiaryComment> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(DiaryComment::getParentCommentId, parentCommentId)
.eq(DiaryComment::getIsDeleted, 0)
.orderByAsc(DiaryComment::getPublishTime);
return this.list(wrapper);
}
@Override
public List<DiaryComment> getByCommentType(String commentType) {
LambdaQueryWrapper<DiaryComment> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(DiaryComment::getCommentType, commentType)
.eq(DiaryComment::getIsDeleted, 0)
.orderByDesc(DiaryComment::getPublishTime);
return this.list(wrapper);
}
@Override
public List<DiaryComment> getByDiaryIdAndCommentType(String diaryId, String commentType) {
LambdaQueryWrapper<DiaryComment> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(DiaryComment::getDiaryId, diaryId)
.eq(DiaryComment::getCommentType, commentType)
.eq(DiaryComment::getIsDeleted, 0)
.orderByDesc(DiaryComment::getPublishTime);
return this.list(wrapper);
}
@Override
public boolean incrementLikeCount(String commentId) {
LambdaUpdateWrapper<DiaryComment> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(DiaryComment::getId, commentId)
.setSql("like_count = like_count + 1");
return this.update(wrapper);
}
@Override
public boolean decrementLikeCount(String commentId) {
LambdaUpdateWrapper<DiaryComment> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(DiaryComment::getId, commentId)
.setSql("like_count = GREATEST(like_count - 1, 0)");
return this.update(wrapper);
}
@Override
public boolean incrementReplyCount(String commentId) {
LambdaUpdateWrapper<DiaryComment> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(DiaryComment::getId, commentId)
.setSql("reply_count = reply_count + 1");
return this.update(wrapper);
}
@Override
public boolean decrementReplyCount(String commentId) {
LambdaUpdateWrapper<DiaryComment> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(DiaryComment::getId, commentId)
.setSql("reply_count = GREATEST(reply_count - 1, 0)");
return this.update(wrapper);
}
@Override
public boolean updateLastReplyTime(String commentId) {
LambdaUpdateWrapper<DiaryComment> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(DiaryComment::getId, commentId)
.set(DiaryComment::getLastReplyTime, LocalDateTime.now());
return this.update(wrapper);
}
@Override
public boolean setTop(String commentId, Integer isTop) {
LambdaUpdateWrapper<DiaryComment> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(DiaryComment::getId, commentId)
.set(DiaryComment::getIsTop, isTop);
return this.update(wrapper);
}
@Override
public Long countByDiaryId(String diaryId) {
LambdaQueryWrapper<DiaryComment> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(DiaryComment::getDiaryId, diaryId)
.eq(DiaryComment::getIsDeleted, 0);
return this.count(wrapper);
}
@Override
public Long countByUserId(String userId) {
LambdaQueryWrapper<DiaryComment> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(DiaryComment::getUserId, userId)
.eq(DiaryComment::getIsDeleted, 0);
return this.count(wrapper);
}
@Override
public Long countByCommentType(String commentType) {
LambdaQueryWrapper<DiaryComment> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(DiaryComment::getCommentType, commentType)
.eq(DiaryComment::getIsDeleted, 0);
return this.count(wrapper);
}
@Override
public Long countReplies(String parentCommentId) {
LambdaQueryWrapper<DiaryComment> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(DiaryComment::getParentCommentId, parentCommentId)
.eq(DiaryComment::getIsDeleted, 0);
return this.count(wrapper);
}
@Override
public DiaryComment createComment(String diaryId, String userId, String content, List<String> images,
String parentCommentId, Integer isAnonymous) {
public DiaryCommentResponse createCommentWithResponse(DiaryCommentCreateRequest request) {
DiaryComment comment = DiaryComment.builder()
.diaryId(diaryId)
.userId(userId)
.content(content)
.images(convertListToJson(images))
.parentCommentId(parentCommentId)
.id(snowflakeIdGenerator.nextIdAsString()) // 使用雪花算法生成ID
.diaryId(request.getDiaryId())
.userId(request.getUserId())
.content(request.getContent())
.images(convertListToJson(request.getImages()))
.parentCommentId(request.getParentCommentId())
.commentType("user")
.likeCount(0)
.replyCount(0)
.isAnonymous(isAnonymous)
.isAnonymous(request.getIsAnonymous())
.isTop(0)
.status("published")
.publishTime(LocalDateTime.now())
.build();
this.save(comment);
// 如果有父评论,更新父评论的回复数
if (StringUtils.hasText(parentCommentId)) {
this.incrementReplyCount(parentCommentId);
this.updateLastReplyTime(parentCommentId);
if (StringUtils.hasText(request.getParentCommentId())) {
this.incrementReplyCount(request.getParentCommentId());
this.updateLastReplyTime(request.getParentCommentId());
}
return comment;
return convertToResponse(comment);
}
@Override
public DiaryComment createAiComment(String diaryId, String content, String aiCommentSource,
BigDecimal emotionScore, BigDecimal sentimentScore) {
DiaryComment comment = DiaryComment.builder()
.diaryId(diaryId)
.userId("system") // AI评论使用system用户ID
.content(content)
.commentType("ai")
.aiCommentSource(aiCommentSource)
.likeCount(0)
.replyCount(0)
.isAnonymous(0)
.isTop(0)
.status("published")
.publishTime(LocalDateTime.now())
.emotionScore(emotionScore)
.sentimentScore(sentimentScore)
.build();
this.save(comment);
return comment;
}
@Override
public boolean updateComment(String commentId, String content, List<String> images) {
public DiaryCommentResponse updateCommentWithResponse(DiaryCommentCreateRequest request) {
LambdaUpdateWrapper<DiaryComment> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(DiaryComment::getId, commentId)
.set(StringUtils.hasText(content), DiaryComment::getContent, content)
.set(images != null, DiaryComment::getImages, convertListToJson(images));
return this.update(wrapper);
wrapper.eq(DiaryComment::getId, request.getId())
.set(StringUtils.hasText(request.getContent()), DiaryComment::getContent, request.getContent())
.set(request.getImages() != null, DiaryComment::getImages, convertListToJson(request.getImages()))
.set(DiaryComment::getUpdateTime, LocalDateTime.now());
boolean updated = this.update(wrapper);
if (!updated) {
return null;
}
DiaryComment updatedComment = this.getById(request.getId());
return updatedComment != null ? convertToResponse(updatedComment) : null;
}
@Override
@@ -241,7 +145,8 @@ public class DiaryCommentServiceImpl extends ServiceImpl<DiaryCommentMapper, Dia
public boolean softDeleteComment(String commentId) {
LambdaUpdateWrapper<DiaryComment> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(DiaryComment::getId, commentId)
.set(DiaryComment::getIsDeleted, 1);
.set(DiaryComment::getIsDeleted, 1)
.set(DiaryComment::getUpdateTime, LocalDateTime.now());
return this.update(wrapper);
}
@@ -249,22 +154,52 @@ public class DiaryCommentServiceImpl extends ServiceImpl<DiaryCommentMapper, Dia
public boolean restoreComment(String commentId) {
LambdaUpdateWrapper<DiaryComment> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(DiaryComment::getId, commentId)
.set(DiaryComment::getIsDeleted, 0);
.set(DiaryComment::getIsDeleted, 0)
.set(DiaryComment::getUpdateTime, LocalDateTime.now());
return this.update(wrapper);
}
@Override
public List<DiaryComment> getCommentTree(String diaryId) {
public boolean incrementLikeCount(String commentId) {
LambdaUpdateWrapper<DiaryComment> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(DiaryComment::getId, commentId)
.setSql("like_count = like_count + 1")
.set(DiaryComment::getUpdateTime, LocalDateTime.now());
return this.update(wrapper);
}
@Override
public boolean decrementLikeCount(String commentId) {
LambdaUpdateWrapper<DiaryComment> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(DiaryComment::getId, commentId)
.setSql("like_count = GREATEST(like_count - 1, 0)")
.set(DiaryComment::getUpdateTime, LocalDateTime.now());
return this.update(wrapper);
}
@Override
public boolean setTop(String commentId, Integer isTop) {
LambdaUpdateWrapper<DiaryComment> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(DiaryComment::getId, commentId)
.set(DiaryComment::getIsTop, isTop)
.set(DiaryComment::getUpdateTime, LocalDateTime.now());
return this.update(wrapper);
}
/**
* 获取评论树结构
*/
private List<DiaryComment> getCommentTree(String diaryId) {
// 获取所有顶级评论(没有父评论的评论)
LambdaQueryWrapper<DiaryComment> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(DiaryComment::getDiaryId, diaryId)
.isNull(DiaryComment::getParentCommentId)
.eq(DiaryComment::getIsDeleted, 0)
.orderByDesc(DiaryComment::getIsTop)
.orderByDesc(DiaryComment::getPublishTime);
.isNull(DiaryComment::getParentCommentId)
.eq(DiaryComment::getIsDeleted, 0)
.orderByDesc(DiaryComment::getIsTop)
.orderByDesc(DiaryComment::getPublishTime);
List<DiaryComment> topComments = this.list(wrapper);
// 为每个顶级评论加载回复
return topComments.stream()
.peek(comment -> {
@@ -274,6 +209,103 @@ public class DiaryCommentServiceImpl extends ServiceImpl<DiaryCommentMapper, Dia
.collect(Collectors.toList());
}
/**
* 根据父评论ID查询回复列表
*/
private List<DiaryComment> getRepliesByParentId(String parentCommentId) {
LambdaQueryWrapper<DiaryComment> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(DiaryComment::getParentCommentId, parentCommentId)
.eq(DiaryComment::getIsDeleted, 0)
.orderByAsc(DiaryComment::getPublishTime);
return this.list(wrapper);
}
/**
* 增加回复数
*/
private boolean incrementReplyCount(String commentId) {
LambdaUpdateWrapper<DiaryComment> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(DiaryComment::getId, commentId)
.setSql("reply_count = reply_count + 1")
.set(DiaryComment::getUpdateTime, LocalDateTime.now());
return this.update(wrapper);
}
/**
* 减少回复数
*/
private boolean decrementReplyCount(String commentId) {
LambdaUpdateWrapper<DiaryComment> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(DiaryComment::getId, commentId)
.setSql("reply_count = GREATEST(reply_count - 1, 0)")
.set(DiaryComment::getUpdateTime, LocalDateTime.now());
return this.update(wrapper);
}
/**
* 更新最后回复时间
*/
private boolean updateLastReplyTime(String commentId) {
LambdaUpdateWrapper<DiaryComment> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(DiaryComment::getId, commentId)
.set(DiaryComment::getLastReplyTime, LocalDateTime.now())
.set(DiaryComment::getUpdateTime, LocalDateTime.now());
return this.update(wrapper);
}
/**
* 转换为响应对象
*/
private DiaryCommentResponse convertToResponse(DiaryComment comment) {
DiaryCommentResponse response = new DiaryCommentResponse();
BeanUtils.copyProperties(comment, response);
// 转换时间格式
if (comment.getPublishTime() != null) {
response.setPublishTime(comment.getPublishTime().format(DATE_TIME_FORMATTER));
}
if (comment.getLastReplyTime() != null) {
response.setLastReplyTime(comment.getLastReplyTime().format(DATE_TIME_FORMATTER));
}
if (comment.getCreateTime() != null) {
response.setCreateTime(comment.getCreateTime().format(DATE_TIME_FORMATTER));
}
if (comment.getUpdateTime() != null) {
response.setUpdateTime(comment.getUpdateTime().format(DATE_TIME_FORMATTER));
}
// 转换JSON字段
try {
if (comment.getImages() != null) {
response.setImages(objectMapper.readValue(comment.getImages(), new TypeReference<List<String>>() {
}));
}
if (comment.getMetadata() != null) {
response.setMetadata(objectMapper.readValue(comment.getMetadata(), Object.class));
}
} catch (JsonProcessingException e) {
// 忽略JSON解析错误
}
return response;
}
/**
* 转换分页对象为响应对象
*/
private PageResult<DiaryCommentResponse> convertPageToResponse(IPage<DiaryComment> page) {
PageResult<DiaryCommentResponse> responsePage = new PageResult<>();
responsePage.setCurrent(page.getCurrent());
responsePage.setSize(page.getSize());
responsePage.setTotal(page.getTotal());
responsePage.setPages(page.getPages());
responsePage.setRecords(
page.getRecords().stream()
.map(this::convertToResponse)
.collect(Collectors.toList()));
return responsePage;
}
/**
* 将List转换为JSON字符串
*/
@@ -287,4 +319,4 @@ public class DiaryCommentServiceImpl extends ServiceImpl<DiaryCommentMapper, Dia
return null;
}
}
}
}
@@ -5,24 +5,30 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.emotion.common.BasePageRequest;
import com.emotion.common.PageResult;
import com.emotion.dto.request.DiaryPostCreateRequest;
import com.emotion.dto.request.DiaryPostPageRequest;
import com.emotion.dto.request.DiaryPostUpdateRequest;
import com.emotion.dto.response.DiaryPostResponse;
import com.emotion.entity.DiaryPost;
import com.emotion.mapper.DiaryPostMapper;
import com.emotion.service.DiaryPostService;
import com.emotion.service.DiaryCommentService;
import com.emotion.service.AiChatService;
import com.emotion.dto.request.DiaryPostCreateRequest;
import com.emotion.dto.response.DiaryPostResponse;
import com.emotion.util.SnowflakeIdGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;
/**
* 用户日记服务实现类
@@ -39,112 +45,153 @@ public class DiaryPostServiceImpl extends ServiceImpl<DiaryPostMapper, DiaryPost
private DiaryCommentService diaryCommentService;
@Autowired
private ObjectMapper objectMapper;
@Autowired
private SnowflakeIdGenerator snowflakeIdGenerator;
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@Override
public IPage<DiaryPost> getPage(BasePageRequest request) {
public PageResult<DiaryPostResponse> getPageWithResponse(DiaryPostPageRequest request) {
Page<DiaryPost> page = new Page<>(request.getCurrent(), request.getSize());
LambdaQueryWrapper<DiaryPost> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(DiaryPost::getIsDeleted, 0)
.orderByDesc(DiaryPost::getPriority)
// 基础查询条件
wrapper.eq(DiaryPost::getIsDeleted, 0);
// 根据请求参数添加查询条件
if (StringUtils.hasText(request.getUserId())) {
wrapper.eq(DiaryPost::getUserId, request.getUserId());
}
if (Boolean.TRUE.equals(request.getPublicOnly())) {
wrapper.eq(DiaryPost::getIsPublic, 1)
.eq(DiaryPost::getStatus, "published");
}
if (Boolean.TRUE.equals(request.getFeaturedOnly())) {
wrapper.eq(DiaryPost::getFeatured, 1)
.eq(DiaryPost::getIsPublic, 1)
.eq(DiaryPost::getStatus, "published");
}
if (StringUtils.hasText(request.getMood())) {
wrapper.eq(DiaryPost::getMood, request.getMood());
}
if (StringUtils.hasText(request.getTag())) {
// 标签查询可能需要特殊处理,因为tags字段是JSON格式
wrapper.like(DiaryPost::getTags, request.getTag());
}
// 排序
wrapper.orderByDesc(DiaryPost::getPriority)
.orderByDesc(DiaryPost::getPublishTime);
return this.page(page, wrapper);
IPage<DiaryPost> resultPage = this.page(page, wrapper);
List<DiaryPostResponse> responses = resultPage.getRecords().stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
return createPageResult(resultPage, responses);
}
@Override
public IPage<DiaryPost> getPageByUserId(String userId, BasePageRequest request) {
Page<DiaryPost> page = new Page<>(request.getCurrent(), request.getSize());
LambdaQueryWrapper<DiaryPost> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(DiaryPost::getUserId, userId)
.eq(DiaryPost::getIsDeleted, 0)
.orderByDesc(DiaryPost::getPriority)
.orderByDesc(DiaryPost::getPublishTime);
return this.page(page, wrapper);
public DiaryPostResponse getDiaryPostResponseById(String id) {
DiaryPost diaryPost = this.getById(id);
if (diaryPost == null) {
return null;
}
// 增加浏览数
incrementViewCount(id);
return convertToResponse(diaryPost);
}
@Override
public IPage<DiaryPost> getPublicPageByUserId(String userId, BasePageRequest request) {
Page<DiaryPost> page = new Page<>(request.getCurrent(), request.getSize());
LambdaQueryWrapper<DiaryPost> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(DiaryPost::getUserId, userId)
.eq(DiaryPost::getIsPublic, 1)
.eq(DiaryPost::getStatus, "published")
.eq(DiaryPost::getIsDeleted, 0)
.orderByDesc(DiaryPost::getPriority)
.orderByDesc(DiaryPost::getPublishTime);
return this.page(page, wrapper);
public DiaryPostResponse createDiaryPostWithResponse(DiaryPostCreateRequest request) {
// 处理标题:如果为空,则设置为null或生成默认标题
String title = request.getTitle();
if (title == null || title.trim().isEmpty()) {
// 可以选择设置为null,或者生成一个默认标题
// 这里我们设置为null,让数据库使用默认值
title = null;
}
DiaryPost diaryPost = DiaryPost.builder()
.id(snowflakeIdGenerator.nextIdAsString()) // 使用雪花算法生成ID
.userId(request.getUserId())
.title(title)
.content(request.getContent())
.images(convertListToJson(request.getImages()))
.videos(convertListToJson(request.getVideos()))
.location(request.getLocation())
.weather(request.getWeather())
.mood(request.getMood())
.tags(convertListToJson(request.getTags()))
.isPublic(request.getIsPublic())
.isAnonymous(request.getIsAnonymous())
.viewCount(0)
.likeCount(0)
.commentCount(0)
.shareCount(0)
.publishTime(LocalDateTime.now())
.status("published")
.priority(0)
.featured(0)
.build();
this.save(diaryPost);
return convertToResponse(diaryPost);
}
@Override
public IPage<DiaryPost> getFeaturedPage(BasePageRequest request) {
Page<DiaryPost> page = new Page<>(request.getCurrent(), request.getSize());
LambdaQueryWrapper<DiaryPost> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(DiaryPost::getFeatured, 1)
.eq(DiaryPost::getIsPublic, 1)
.eq(DiaryPost::getStatus, "published")
.eq(DiaryPost::getIsDeleted, 0)
.orderByDesc(DiaryPost::getPriority)
.orderByDesc(DiaryPost::getPublishTime);
return this.page(page, wrapper);
public DiaryPostResponse updateDiaryPostWithResponse(DiaryPostUpdateRequest request) {
LambdaUpdateWrapper<DiaryPost> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(DiaryPost::getId, request.getId())
.set(StringUtils.hasText(request.getTitle()), DiaryPost::getTitle, request.getTitle())
.set(StringUtils.hasText(request.getContent()), DiaryPost::getContent, request.getContent())
.set(request.getImages() != null, DiaryPost::getImages, convertListToJson(request.getImages()))
.set(request.getVideos() != null, DiaryPost::getVideos, convertListToJson(request.getVideos()))
.set(StringUtils.hasText(request.getLocation()), DiaryPost::getLocation, request.getLocation())
.set(StringUtils.hasText(request.getWeather()), DiaryPost::getWeather, request.getWeather())
.set(StringUtils.hasText(request.getMood()), DiaryPost::getMood, request.getMood())
.set(request.getTags() != null, DiaryPost::getTags, convertListToJson(request.getTags()))
.set(request.getIsPublic() != null, DiaryPost::getIsPublic, request.getIsPublic())
.set(request.getIsAnonymous() != null, DiaryPost::getIsAnonymous, request.getIsAnonymous())
.set(StringUtils.hasText(request.getStatus()), DiaryPost::getStatus, request.getStatus())
.set(DiaryPost::getUpdateTime, LocalDateTime.now());
boolean updated = this.update(wrapper);
if (!updated) {
return null;
}
DiaryPost updatedDiaryPost = this.getById(request.getId());
return convertToResponse(updatedDiaryPost);
}
@Override
public List<DiaryPost> getByStatus(String status) {
LambdaQueryWrapper<DiaryPost> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(DiaryPost::getStatus, status)
.eq(DiaryPost::getIsDeleted, 0)
.orderByDesc(DiaryPost::getPublishTime);
return this.list(wrapper);
public boolean deleteDiaryPost(String diaryId) {
return this.removeById(diaryId);
}
@Override
public List<DiaryPost> getByUserIdAndStatus(String userId, String status) {
LambdaQueryWrapper<DiaryPost> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(DiaryPost::getUserId, userId)
.eq(DiaryPost::getStatus, status)
.eq(DiaryPost::getIsDeleted, 0)
.orderByDesc(DiaryPost::getPublishTime);
return this.list(wrapper);
public boolean softDeleteDiaryPost(String diaryId) {
LambdaUpdateWrapper<DiaryPost> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(DiaryPost::getId, diaryId)
.set(DiaryPost::getIsDeleted, 1)
.set(DiaryPost::getUpdateTime, LocalDateTime.now());
return this.update(wrapper);
}
@Override
public List<DiaryPost> getByMood(String mood) {
LambdaQueryWrapper<DiaryPost> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(DiaryPost::getMood, mood)
.eq(DiaryPost::getIsPublic, 1)
.eq(DiaryPost::getStatus, "published")
.eq(DiaryPost::getIsDeleted, 0)
.orderByDesc(DiaryPost::getPublishTime);
return this.list(wrapper);
}
@Override
public List<DiaryPost> getByTags(List<String> tags) {
// 这里需要根据实际需求实现标签查询逻辑
// 由于tags字段是JSON格式,可能需要使用数据库的JSON查询功能
LambdaQueryWrapper<DiaryPost> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(DiaryPost::getIsPublic, 1)
.eq(DiaryPost::getStatus, "published")
.eq(DiaryPost::getIsDeleted, 0)
.orderByDesc(DiaryPost::getPublishTime);
return this.list(wrapper);
}
@Override
public List<DiaryPost> getByLocation(String location) {
LambdaQueryWrapper<DiaryPost> wrapper = new LambdaQueryWrapper<>();
wrapper.like(DiaryPost::getLocation, location)
.eq(DiaryPost::getIsPublic, 1)
.eq(DiaryPost::getStatus, "published")
.eq(DiaryPost::getIsDeleted, 0)
.orderByDesc(DiaryPost::getPublishTime);
return this.list(wrapper);
public boolean restoreDiaryPost(String diaryId) {
LambdaUpdateWrapper<DiaryPost> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(DiaryPost::getId, diaryId)
.set(DiaryPost::getIsDeleted, 0)
.set(DiaryPost::getUpdateTime, LocalDateTime.now());
return this.update(wrapper);
}
@Override
public boolean incrementViewCount(String diaryId) {
LambdaUpdateWrapper<DiaryPost> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(DiaryPost::getId, diaryId)
.setSql("view_count = view_count + 1");
.setSql("view_count = view_count + 1")
.set(DiaryPost::getUpdateTime, LocalDateTime.now());
return this.update(wrapper);
}
@@ -152,7 +199,8 @@ public class DiaryPostServiceImpl extends ServiceImpl<DiaryPostMapper, DiaryPost
public boolean incrementLikeCount(String diaryId) {
LambdaUpdateWrapper<DiaryPost> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(DiaryPost::getId, diaryId)
.setSql("like_count = like_count + 1");
.setSql("like_count = like_count + 1")
.set(DiaryPost::getUpdateTime, LocalDateTime.now());
return this.update(wrapper);
}
@@ -160,7 +208,8 @@ public class DiaryPostServiceImpl extends ServiceImpl<DiaryPostMapper, DiaryPost
public boolean decrementLikeCount(String diaryId) {
LambdaUpdateWrapper<DiaryPost> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(DiaryPost::getId, diaryId)
.setSql("like_count = GREATEST(like_count - 1, 0)");
.setSql("like_count = GREATEST(like_count - 1, 0)")
.set(DiaryPost::getUpdateTime, LocalDateTime.now());
return this.update(wrapper);
}
@@ -168,7 +217,8 @@ public class DiaryPostServiceImpl extends ServiceImpl<DiaryPostMapper, DiaryPost
public boolean incrementCommentCount(String diaryId) {
LambdaUpdateWrapper<DiaryPost> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(DiaryPost::getId, diaryId)
.setSql("comment_count = comment_count + 1");
.setSql("comment_count = comment_count + 1")
.set(DiaryPost::getUpdateTime, LocalDateTime.now());
return this.update(wrapper);
}
@@ -176,7 +226,8 @@ public class DiaryPostServiceImpl extends ServiceImpl<DiaryPostMapper, DiaryPost
public boolean decrementCommentCount(String diaryId) {
LambdaUpdateWrapper<DiaryPost> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(DiaryPost::getId, diaryId)
.setSql("comment_count = GREATEST(comment_count - 1, 0)");
.setSql("comment_count = GREATEST(comment_count - 1, 0)")
.set(DiaryPost::getUpdateTime, LocalDateTime.now());
return this.update(wrapper);
}
@@ -184,7 +235,8 @@ public class DiaryPostServiceImpl extends ServiceImpl<DiaryPostMapper, DiaryPost
public boolean incrementShareCount(String diaryId) {
LambdaUpdateWrapper<DiaryPost> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(DiaryPost::getId, diaryId)
.setSql("share_count = share_count + 1");
.setSql("share_count = share_count + 1")
.set(DiaryPost::getUpdateTime, LocalDateTime.now());
return this.update(wrapper);
}
@@ -192,7 +244,8 @@ public class DiaryPostServiceImpl extends ServiceImpl<DiaryPostMapper, DiaryPost
public boolean updateLastCommentTime(String diaryId) {
LambdaUpdateWrapper<DiaryPost> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(DiaryPost::getId, diaryId)
.set(DiaryPost::getLastCommentTime, LocalDateTime.now());
.set(DiaryPost::getLastCommentTime, LocalDateTime.now())
.set(DiaryPost::getUpdateTime, LocalDateTime.now());
return this.update(wrapper);
}
@@ -200,7 +253,8 @@ public class DiaryPostServiceImpl extends ServiceImpl<DiaryPostMapper, DiaryPost
public boolean setFeatured(String diaryId, Integer featured) {
LambdaUpdateWrapper<DiaryPost> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(DiaryPost::getId, diaryId)
.set(DiaryPost::getFeatured, featured);
.set(DiaryPost::getFeatured, featured)
.set(DiaryPost::getUpdateTime, LocalDateTime.now());
return this.update(wrapper);
}
@@ -208,7 +262,8 @@ public class DiaryPostServiceImpl extends ServiceImpl<DiaryPostMapper, DiaryPost
public boolean setPriority(String diaryId, Integer priority) {
LambdaUpdateWrapper<DiaryPost> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(DiaryPost::getId, diaryId)
.set(DiaryPost::getPriority, priority);
.set(DiaryPost::getPriority, priority)
.set(DiaryPost::getUpdateTime, LocalDateTime.now());
return this.update(wrapper);
}
@@ -239,26 +294,12 @@ public class DiaryPostServiceImpl extends ServiceImpl<DiaryPostMapper, DiaryPost
}
@Override
public Long countByStatus(String status) {
LambdaQueryWrapper<DiaryPost> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(DiaryPost::getStatus, status)
.eq(DiaryPost::getIsDeleted, 0);
return this.count(wrapper);
}
@Override
public DiaryPost createDiaryPost(com.emotion.dto.request.DiaryPostCreateRequest request) {
// 处理标题:如果为空,则设置为null或生成默认标题
String title = request.getTitle();
if (title == null || title.trim().isEmpty()) {
// 可以选择设置为null,或者生成一个默认标题
// 这里我们设置为null,让数据库使用默认值
title = null;
}
public DiaryPostResponse publishDiaryWithAiComment(DiaryPostCreateRequest request) {
// 1. 保存日记
DiaryPost diaryPost = DiaryPost.builder()
.id(snowflakeIdGenerator.nextIdAsString()) // 使用雪花算法生成ID
.userId(request.getUserId())
.title(title)
.title(request.getTitle())
.content(request.getContent())
.images(convertListToJson(request.getImages()))
.videos(convertListToJson(request.getVideos()))
@@ -277,69 +318,8 @@ public class DiaryPostServiceImpl extends ServiceImpl<DiaryPostMapper, DiaryPost
.priority(0)
.featured(0)
.build();
this.save(diaryPost);
return diaryPost;
}
@Override
public boolean updateDiaryPost(String diaryId, com.emotion.dto.request.DiaryPostUpdateRequest request) {
LambdaUpdateWrapper<DiaryPost> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(DiaryPost::getId, diaryId)
.set(StringUtils.hasText(request.getTitle()), DiaryPost::getTitle, request.getTitle())
.set(StringUtils.hasText(request.getContent()), DiaryPost::getContent, request.getContent())
.set(request.getImages() != null, DiaryPost::getImages, convertListToJson(request.getImages()))
.set(request.getVideos() != null, DiaryPost::getVideos, convertListToJson(request.getVideos()))
.set(StringUtils.hasText(request.getLocation()), DiaryPost::getLocation, request.getLocation())
.set(StringUtils.hasText(request.getWeather()), DiaryPost::getWeather, request.getWeather())
.set(StringUtils.hasText(request.getMood()), DiaryPost::getMood, request.getMood())
.set(request.getTags() != null, DiaryPost::getTags, convertListToJson(request.getTags()))
.set(request.getIsPublic() != null, DiaryPost::getIsPublic, request.getIsPublic())
.set(request.getIsAnonymous() != null, DiaryPost::getIsAnonymous, request.getIsAnonymous())
.set(StringUtils.hasText(request.getStatus()), DiaryPost::getStatus, request.getStatus());
return this.update(wrapper);
}
@Override
public boolean deleteDiaryPost(String diaryId) {
return this.removeById(diaryId);
}
@Override
public boolean softDeleteDiaryPost(String diaryId) {
LambdaUpdateWrapper<DiaryPost> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(DiaryPost::getId, diaryId)
.set(DiaryPost::getIsDeleted, 1);
return this.update(wrapper);
}
@Override
public boolean restoreDiaryPost(String diaryId) {
LambdaUpdateWrapper<DiaryPost> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(DiaryPost::getId, diaryId)
.set(DiaryPost::getIsDeleted, 0);
return this.update(wrapper);
}
@Override
public boolean addAiComment(String diaryId, String aiComment, Object aiEmotionAnalysis,
BigDecimal aiSentimentScore, List<String> aiKeywords, String aiSuggestions) {
LambdaUpdateWrapper<DiaryPost> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(DiaryPost::getId, diaryId)
.set(DiaryPost::getAiComment, aiComment)
.set(DiaryPost::getAiCommentTime, LocalDateTime.now())
.set(DiaryPost::getAiEmotionAnalysis, convertObjectToJson(aiEmotionAnalysis))
.set(DiaryPost::getAiSentimentScore, aiSentimentScore)
.set(DiaryPost::getAiKeywords, convertListToJson(aiKeywords))
.set(DiaryPost::getAiSuggestions, aiSuggestions);
return this.update(wrapper);
}
@Override
public com.emotion.dto.response.DiaryPostResponse publishDiaryWithAiComment(com.emotion.dto.request.DiaryPostCreateRequest request) {
// 1. 保存日记
DiaryPost diaryPost = createDiaryPost(request);
// 2. 生成AI评论
String aiComment = null;
try {
@@ -350,13 +330,14 @@ public class DiaryPostServiceImpl extends ServiceImpl<DiaryPostMapper, DiaryPost
}
// 3. 写入AI评论到diary_comment表
if (aiComment != null) {
diaryCommentService.createAiComment(
diaryPost.getId(),
aiComment,
"diary_ai_summary",
null,
null
);
// 使用createCommentWithResponse方法创建AI评论
com.emotion.dto.request.DiaryCommentCreateRequest commentRequest = new com.emotion.dto.request.DiaryCommentCreateRequest();
commentRequest.setDiaryId(diaryPost.getId());
commentRequest.setUserId("system"); // AI评论使用system用户ID
commentRequest.setContent(aiComment);
commentRequest.setIsAnonymous(0);
diaryCommentService.createCommentWithResponse(commentRequest);
addAiComment(
diaryPost.getId(),
aiComment,
@@ -367,53 +348,37 @@ public class DiaryPostServiceImpl extends ServiceImpl<DiaryPostMapper, DiaryPost
);
}
// 4. 返回日记详情(含AI评论)
com.emotion.dto.response.DiaryPostResponse response = new com.emotion.dto.response.DiaryPostResponse();
org.springframework.beans.BeanUtils.copyProperties(diaryPost, response);
// 查询AI评论
List<com.emotion.entity.DiaryComment> aiComments = diaryCommentService.getByDiaryIdAndCommentType(diaryPost.getId(), "ai");
if (!aiComments.isEmpty()) {
response.setAiComment(aiComments.get(0).getContent());
}
// 转换时间格式
if (diaryPost.getPublishTime() != null) {
response.setPublishTime(diaryPost.getPublishTime().format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
}
if (diaryPost.getLastCommentTime() != null) {
response.setLastCommentTime(diaryPost.getLastCommentTime().format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
}
if (diaryPost.getAiCommentTime() != null) {
response.setAiCommentTime(diaryPost.getAiCommentTime().format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
}
if (diaryPost.getCreateTime() != null) {
response.setCreateTime(diaryPost.getCreateTime().format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
}
if (diaryPost.getUpdateTime() != null) {
response.setUpdateTime(diaryPost.getUpdateTime().format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
}
// 转换JSON字段
try {
if (diaryPost.getImages() != null) {
response.setImages(objectMapper.readValue(diaryPost.getImages(), new com.fasterxml.jackson.core.type.TypeReference<List<String>>() {}));
}
if (diaryPost.getVideos() != null) {
response.setVideos(objectMapper.readValue(diaryPost.getVideos(), new com.fasterxml.jackson.core.type.TypeReference<List<String>>() {}));
}
if (diaryPost.getTags() != null) {
response.setTags(objectMapper.readValue(diaryPost.getTags(), new com.fasterxml.jackson.core.type.TypeReference<List<String>>() {}));
}
if (diaryPost.getAiKeywords() != null) {
response.setAiKeywords(objectMapper.readValue(diaryPost.getAiKeywords(), new com.fasterxml.jackson.core.type.TypeReference<List<String>>() {}));
}
if (diaryPost.getAiEmotionAnalysis() != null) {
response.setAiEmotionAnalysis(objectMapper.readValue(diaryPost.getAiEmotionAnalysis(), Object.class));
}
if (diaryPost.getMetadata() != null) {
response.setMetadata(objectMapper.readValue(diaryPost.getMetadata(), Object.class));
}
} catch (com.fasterxml.jackson.core.JsonProcessingException e) {
// 忽略JSON解析错误
}
return response;
return convertToResponse(diaryPost);
}
/**
* 添加AI评论
*/
private boolean addAiComment(String diaryId, String aiComment, Object aiEmotionAnalysis,
BigDecimal aiSentimentScore, List<String> aiKeywords, String aiSuggestions) {
LambdaUpdateWrapper<DiaryPost> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(DiaryPost::getId, diaryId)
.set(DiaryPost::getAiComment, aiComment)
.set(DiaryPost::getAiCommentTime, LocalDateTime.now())
.set(DiaryPost::getAiEmotionAnalysis, convertObjectToJson(aiEmotionAnalysis))
.set(DiaryPost::getAiSentimentScore, aiSentimentScore)
.set(DiaryPost::getAiKeywords, convertListToJson(aiKeywords))
.set(DiaryPost::getAiSuggestions, aiSuggestions)
.set(DiaryPost::getUpdateTime, LocalDateTime.now());
return this.update(wrapper);
}
/**
* 创建PageResult对象
*/
private <T> PageResult<T> createPageResult(IPage<?> page, List<T> records) {
PageResult<T> pageResult = new PageResult<>();
pageResult.setCurrent(page.getCurrent());
pageResult.setSize(page.getSize());
pageResult.setTotal(page.getTotal());
pageResult.setPages(page.getPages());
pageResult.setRecords(records);
return pageResult;
}
/**
@@ -443,4 +408,60 @@ public class DiaryPostServiceImpl extends ServiceImpl<DiaryPostMapper, DiaryPost
return null;
}
}
}
/**
* 转换实体为响应DTO
*/
private DiaryPostResponse convertToResponse(DiaryPost diaryPost) {
DiaryPostResponse response = new DiaryPostResponse();
BeanUtils.copyProperties(diaryPost, response);
// 转换时间格式
if (diaryPost.getPublishTime() != null) {
response.setPublishTime(diaryPost.getPublishTime().format(DATE_TIME_FORMATTER));
}
if (diaryPost.getLastCommentTime() != null) {
response.setLastCommentTime(diaryPost.getLastCommentTime().format(DATE_TIME_FORMATTER));
}
if (diaryPost.getAiCommentTime() != null) {
response.setAiCommentTime(diaryPost.getAiCommentTime().format(DATE_TIME_FORMATTER));
}
if (diaryPost.getCreateTime() != null) {
response.setCreateTime(diaryPost.getCreateTime().format(DATE_TIME_FORMATTER));
}
if (diaryPost.getUpdateTime() != null) {
response.setUpdateTime(diaryPost.getUpdateTime().format(DATE_TIME_FORMATTER));
}
// 转换JSON字段
try {
if (diaryPost.getImages() != null) {
response.setImages(objectMapper.readValue(diaryPost.getImages(), new TypeReference<List<String>>() {
}));
}
if (diaryPost.getVideos() != null) {
response.setVideos(objectMapper.readValue(diaryPost.getVideos(), new TypeReference<List<String>>() {
}));
}
if (diaryPost.getTags() != null) {
response.setTags(objectMapper.readValue(diaryPost.getTags(), new TypeReference<List<String>>() {
}));
}
if (diaryPost.getAiKeywords() != null) {
response.setAiKeywords(
objectMapper.readValue(diaryPost.getAiKeywords(), new TypeReference<List<String>>() {
}));
}
if (diaryPost.getAiEmotionAnalysis() != null) {
response.setAiEmotionAnalysis(objectMapper.readValue(diaryPost.getAiEmotionAnalysis(), Object.class));
}
if (diaryPost.getMetadata() != null) {
response.setMetadata(objectMapper.readValue(diaryPost.getMetadata(), Object.class));
}
} catch (JsonProcessingException e) {
// 忽略JSON解析错误
}
return response;
}
}
@@ -5,15 +5,25 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.emotion.common.BasePageRequest;
import com.emotion.common.PageResult;
import com.emotion.dto.request.EmotionAnalysisCreateRequest;
import com.emotion.dto.request.EmotionAnalysisPageRequest;
import com.emotion.dto.request.EmotionAnalysisUpdateRequest;
import com.emotion.dto.response.EmotionAnalysisResponse;
import com.emotion.entity.EmotionAnalysis;
import com.emotion.mapper.EmotionAnalysisMapper;
import com.emotion.service.EmotionAnalysisService;
import com.emotion.util.SnowflakeIdGenerator;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;
/**
* 情绪分析服务实现类
@@ -24,6 +34,11 @@ import java.util.List;
@Service
public class EmotionAnalysisServiceImpl extends ServiceImpl<EmotionAnalysisMapper, EmotionAnalysis> implements EmotionAnalysisService {
@Autowired
private SnowflakeIdGenerator snowflakeIdGenerator;
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@Override
public IPage<EmotionAnalysis> getPage(BasePageRequest request) {
Page<EmotionAnalysis> page = new Page<>(request.getCurrent(), request.getSize());
@@ -173,6 +188,7 @@ public class EmotionAnalysisServiceImpl extends ServiceImpl<EmotionAnalysisMappe
public EmotionAnalysis createEmotionAnalysis(String messageId, String userId, String primaryEmotion,
String polarity, Double intensity, Double confidence) {
EmotionAnalysis analysis = new EmotionAnalysis();
analysis.setId(snowflakeIdGenerator.nextIdAsString()); // 使用雪花算法生成ID
analysis.setMessageId(messageId);
analysis.setCreateBy(userId);
analysis.setPrimaryEmotion(primaryEmotion);
@@ -183,4 +199,162 @@ public class EmotionAnalysisServiceImpl extends ServiceImpl<EmotionAnalysisMappe
this.save(analysis);
return analysis;
}
// 新增的方法实现
@Override
public PageResult<EmotionAnalysisResponse> getPageWithResponse(EmotionAnalysisPageRequest request) {
IPage<EmotionAnalysis> page = getPage(request);
List<EmotionAnalysisResponse> responses = page.getRecords().stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
return createPageResult(page, responses);
}
@Override
public PageResult<EmotionAnalysisResponse> getPageByUserIdWithResponse(String userId,
EmotionAnalysisPageRequest request) {
IPage<EmotionAnalysis> page = getPageByUserId(request, userId);
List<EmotionAnalysisResponse> responses = page.getRecords().stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
return createPageResult(page, responses);
}
@Override
public EmotionAnalysisResponse getEmotionAnalysisResponseById(String id) {
EmotionAnalysis analysis = this.getById(id);
if (analysis == null) {
return null;
}
return convertToResponse(analysis);
}
@Override
public EmotionAnalysisResponse getEmotionAnalysisResponseByMessageId(String messageId) {
EmotionAnalysis analysis = getByMessageId(messageId);
if (analysis == null) {
return null;
}
return convertToResponse(analysis);
}
@Override
public EmotionAnalysisResponse createEmotionAnalysisWithResponse(EmotionAnalysisCreateRequest request) {
EmotionAnalysis analysis = createEmotionAnalysis(
request.getMessageId(),
request.getUserId(),
request.getPrimaryEmotion(),
request.getPolarity(),
request.getIntensity(),
request.getConfidence());
return convertToResponse(analysis);
}
@Override
public EmotionAnalysisResponse updateEmotionAnalysisWithResponse(EmotionAnalysisUpdateRequest request) {
EmotionAnalysis analysis = this.getById(request.getId());
if (analysis == null) {
return null;
}
// 更新字段
if (request.getMessageId() != null) {
analysis.setMessageId(request.getMessageId());
}
if (request.getUserId() != null) {
analysis.setCreateBy(request.getUserId());
}
if (request.getPrimaryEmotion() != null) {
analysis.setPrimaryEmotion(request.getPrimaryEmotion());
}
if (request.getPolarity() != null) {
analysis.setPolarity(request.getPolarity());
}
if (request.getIntensity() != null) {
analysis.setIntensity(BigDecimal.valueOf(request.getIntensity()));
}
if (request.getConfidence() != null) {
analysis.setConfidence(BigDecimal.valueOf(request.getConfidence()));
}
this.updateById(analysis);
return convertToResponse(analysis);
}
@Override
public boolean deleteEmotionAnalysis(String id) {
return this.removeById(id);
}
@Override
public List<EmotionAnalysisResponse> getEmotionAnalysisResponsesByPrimaryEmotion(String primaryEmotion) {
List<EmotionAnalysis> analyses = getByPrimaryEmotion(primaryEmotion);
return analyses.stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
}
@Override
public List<EmotionAnalysisResponse> getEmotionAnalysisResponsesByPolarity(String polarity) {
List<EmotionAnalysis> analyses = getByPolarity(polarity);
return analyses.stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
}
@Override
public List<EmotionAnalysisResponse> getEmotionAnalysisResponsesByUserIdAndEmotion(String userId,
String primaryEmotion) {
List<EmotionAnalysis> analyses = getByUserIdAndEmotion(userId, primaryEmotion);
return analyses.stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
}
@Override
public List<EmotionAnalysisResponse> getEmotionAnalysisResponsesByUserIdAndTimeRange(String userId,
LocalDateTime startTime, LocalDateTime endTime) {
List<EmotionAnalysis> analyses = getByUserIdAndTimeRange(userId, startTime, endTime);
return analyses.stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
}
@Override
public List<EmotionAnalysisResponse> getEmotionAnalysisResponsesRecentByUserId(String userId, Integer limit) {
List<EmotionAnalysis> analyses = getRecentByUserId(userId, limit);
return analyses.stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
}
/**
* 创建PageResult对象
*/
private <T> PageResult<T> createPageResult(IPage<?> page, List<T> records) {
PageResult<T> pageResult = new PageResult<>();
pageResult.setCurrent(page.getCurrent());
pageResult.setSize(page.getSize());
pageResult.setTotal(page.getTotal());
pageResult.setPages(page.getPages());
pageResult.setRecords(records);
return pageResult;
}
/**
* 转换为响应对象
*/
private EmotionAnalysisResponse convertToResponse(EmotionAnalysis analysis) {
EmotionAnalysisResponse response = new EmotionAnalysisResponse();
BeanUtils.copyProperties(analysis, response);
response.setId(analysis.getId());
if (analysis.getCreateTime() != null) {
response.setCreateTime(analysis.getCreateTime().format(DATE_TIME_FORMATTER));
}
if (analysis.getUpdateTime() != null) {
response.setUpdateTime(analysis.getUpdateTime().format(DATE_TIME_FORMATTER));
}
return response;
}
}
@@ -5,17 +5,29 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.emotion.common.BasePageRequest;
import com.emotion.common.PageResult;
import com.emotion.dto.request.EmotionRecordCreateRequest;
import com.emotion.dto.request.EmotionRecordPageRequest;
import com.emotion.dto.request.EmotionRecordUpdateRequest;
import com.emotion.dto.response.EmotionRecordResponse;
import com.emotion.entity.EmotionRecord;
import com.emotion.mapper.EmotionRecordMapper;
import com.emotion.service.EmotionRecordService;
import com.emotion.util.SnowflakeIdGenerator;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.Collections;
import java.util.stream.Collectors;
/**
* 情绪记录服务实现类
@@ -26,6 +38,11 @@ import java.util.Collections;
@Service
public class EmotionRecordServiceImpl extends ServiceImpl<EmotionRecordMapper, EmotionRecord> implements EmotionRecordService {
@Autowired
private SnowflakeIdGenerator snowflakeIdGenerator;
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@Override
public IPage<EmotionRecord> getPage(BasePageRequest request) {
Page<EmotionRecord> page = new Page<>(request.getCurrent(), request.getSize());
@@ -134,20 +151,59 @@ public class EmotionRecordServiceImpl extends ServiceImpl<EmotionRecordMapper, E
@Override
public Double getAvgIntensityByUserId(String userId) {
// 这里需要自定义SQL查询平均值,暂时返回0
return 0.0;
LambdaQueryWrapper<EmotionRecord> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(EmotionRecord::getUserId, userId)
.eq(EmotionRecord::getIsDeleted, 0);
List<EmotionRecord> records = this.list(wrapper);
if (records.isEmpty()) {
return 0.0;
}
double sum = records.stream()
.mapToDouble(record -> record.getIntensity().doubleValue())
.sum();
return sum / records.size();
}
@Override
public Double getAvgIntensityByUserIdAndTimeRange(String userId, LocalDateTime startTime, LocalDateTime endTime) {
// 这里需要自定义SQL查询平均值,暂时返回0
return 0.0;
LambdaQueryWrapper<EmotionRecord> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(EmotionRecord::getUserId, userId)
.between(EmotionRecord::getCreateTime, startTime, endTime)
.eq(EmotionRecord::getIsDeleted, 0);
List<EmotionRecord> records = this.list(wrapper);
if (records.isEmpty()) {
return 0.0;
}
double sum = records.stream()
.mapToDouble(record -> record.getIntensity().doubleValue())
.sum();
return sum / records.size();
}
@Override
public String getMostFrequentEmotionByUserId(String userId) {
// 这里需要自定义SQL查询最常见的情绪类型,暂时返回null
return null;
LambdaQueryWrapper<EmotionRecord> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(EmotionRecord::getUserId, userId)
.eq(EmotionRecord::getIsDeleted, 0);
List<EmotionRecord> records = this.list(wrapper);
if (records.isEmpty()) {
return null;
}
return records.stream()
.collect(Collectors.groupingBy(EmotionRecord::getEmotionType, Collectors.counting()))
.entrySet()
.stream()
.max(Map.Entry.comparingByValue())
.map(Map.Entry::getKey)
.orElse(null);
}
@Override
@@ -181,6 +237,7 @@ public class EmotionRecordServiceImpl extends ServiceImpl<EmotionRecordMapper, E
public EmotionRecord createEmotionRecord(String userId, String emotionType, Double intensity,
String trigger, String location, String notes) {
EmotionRecord record = new EmotionRecord();
record.setId(snowflakeIdGenerator.nextIdAsString()); // 使用雪花算法生成ID
record.setUserId(userId);
record.setEmotionType(emotionType);
record.setIntensity(BigDecimal.valueOf(intensity));
@@ -204,4 +261,223 @@ public class EmotionRecordServiceImpl extends ServiceImpl<EmotionRecordMapper, E
return this.page(page, wrapper);
}
// 新增的方法实现
@Override
public PageResult<EmotionRecordResponse> getPageWithResponse(EmotionRecordPageRequest request) {
IPage<EmotionRecord> page = getPage(request);
List<EmotionRecordResponse> responses = page.getRecords().stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
PageResult<EmotionRecordResponse> pageResult = new PageResult<>();
pageResult.setCurrent(page.getCurrent());
pageResult.setSize(page.getSize());
pageResult.setTotal(page.getTotal());
pageResult.setPages(page.getPages());
pageResult.setRecords(responses);
return pageResult;
}
@Override
public PageResult<EmotionRecordResponse> getPageByUserIdWithResponse(String userId, EmotionRecordPageRequest request) {
IPage<EmotionRecord> page = getPageByUserId(request, userId);
List<EmotionRecordResponse> responses = page.getRecords().stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
PageResult<EmotionRecordResponse> pageResult = new PageResult<>();
pageResult.setCurrent(page.getCurrent());
pageResult.setSize(page.getSize());
pageResult.setTotal(page.getTotal());
pageResult.setPages(page.getPages());
pageResult.setRecords(responses);
return pageResult;
}
@Override
public EmotionRecordResponse getEmotionRecordResponseById(String id) {
EmotionRecord record = this.getById(id);
if (record == null) {
return null;
}
return convertToResponse(record);
}
@Override
public EmotionRecordResponse createEmotionRecordWithResponse(EmotionRecordCreateRequest request) {
EmotionRecord record = new EmotionRecord();
record.setId(snowflakeIdGenerator.nextIdAsString()); // 使用雪花算法生成ID
record.setUserId(request.getUserId());
record.setRecordDate(request.getRecordDate());
record.setEmotionType(request.getEmotionType());
record.setIntensity(request.getIntensity());
record.setTriggers(request.getTriggers());
record.setDescription(request.getDescription());
// 注意:tags字段在实体类中是String类型,需要转换
record.setTags(request.getTags() != null ? request.getTags().toString() : null);
record.setWeather(request.getWeather());
record.setLocation(request.getLocation());
record.setActivity(request.getActivity());
record.setPeople(request.getPeople());
record.setNotes(request.getNotes());
this.save(record);
return convertToResponse(record);
}
@Override
public EmotionRecordResponse updateEmotionRecordWithResponse(EmotionRecordUpdateRequest request) {
EmotionRecord record = this.getById(request.getId());
if (record == null) {
return null;
}
// 更新字段
if (request.getRecordDate() != null) {
record.setRecordDate(request.getRecordDate());
}
if (request.getEmotionType() != null) {
record.setEmotionType(request.getEmotionType());
}
if (request.getIntensity() != null) {
record.setIntensity(request.getIntensity());
}
if (request.getTriggers() != null) {
record.setTriggers(request.getTriggers());
}
if (request.getDescription() != null) {
record.setDescription(request.getDescription());
}
// 注意:tags字段在实体类中是String类型,需要转换
if (request.getTags() != null) {
record.setTags(request.getTags().toString());
}
if (request.getWeather() != null) {
record.setWeather(request.getWeather());
}
if (request.getLocation() != null) {
record.setLocation(request.getLocation());
}
if (request.getActivity() != null) {
record.setActivity(request.getActivity());
}
if (request.getPeople() != null) {
record.setPeople(request.getPeople());
}
if (request.getNotes() != null) {
record.setNotes(request.getNotes());
}
this.updateById(record);
return convertToResponse(record);
}
@Override
public boolean deleteEmotionRecord(String id) {
return this.removeById(id);
}
@Override
public Map<String, Object> getEmotionStats(String userId, String startDate, String endDate) {
Map<String, Object> stats = new HashMap<>();
// 构建查询条件
LambdaQueryWrapper<EmotionRecord> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(EmotionRecord::getUserId, userId)
.eq(EmotionRecord::getIsDeleted, 0);
// 如果提供了日期范围,则添加时间条件
if (StringUtils.hasText(startDate) && StringUtils.hasText(endDate)) {
try {
LocalDateTime start = LocalDate.parse(startDate).atStartOfDay();
LocalDateTime end = LocalDate.parse(endDate).atTime(23, 59, 59);
wrapper.between(EmotionRecord::getCreateTime, start, end);
} catch (Exception e) {
// 如果日期解析失败,忽略日期条件
}
}
// 查询用户的所有情绪记录
List<EmotionRecord> records = this.list(wrapper);
if (records.isEmpty()) {
stats.put("emotionDistribution", new HashMap<>());
stats.put("totalRecords", 0);
stats.put("averageIntensity", 0.0);
stats.put("mostFrequentEmotion", null);
stats.put("emotionTrend", "no_data");
return stats;
}
// 情绪类型分布
Map<String, Long> emotionDistribution = records.stream()
.collect(Collectors.groupingBy(EmotionRecord::getEmotionType, Collectors.counting()));
stats.put("emotionDistribution", emotionDistribution);
stats.put("totalRecords", records.size());
// 平均情绪强度
double avgIntensity = records.stream()
.mapToDouble(record -> record.getIntensity().doubleValue())
.average()
.orElse(0.0);
stats.put("averageIntensity", avgIntensity);
// 最常见的情绪类型
String mostFrequentEmotion = emotionDistribution.entrySet().stream()
.max(Map.Entry.comparingByValue())
.map(Map.Entry::getKey)
.orElse(null);
stats.put("mostFrequentEmotion", mostFrequentEmotion);
// 情绪趋势(简单实现:比较前半段和后半段的平均强度)
if (records.size() > 1) {
int mid = records.size() / 2;
double firstHalfAvg = records.subList(0, mid).stream()
.mapToDouble(record -> record.getIntensity().doubleValue())
.average()
.orElse(0.0);
double secondHalfAvg = records.subList(mid, records.size()).stream()
.mapToDouble(record -> record.getIntensity().doubleValue())
.average()
.orElse(0.0);
if (secondHalfAvg > firstHalfAvg) {
stats.put("emotionTrend", "improving");
} else if (secondHalfAvg < firstHalfAvg) {
stats.put("emotionTrend", "declining");
} else {
stats.put("emotionTrend", "stable");
}
} else {
stats.put("emotionTrend", "insufficient_data");
}
return stats;
}
@Override
public List<EmotionRecordResponse> getRecentByUserIdWithResponse(String userId, Integer limit) {
List<EmotionRecord> records = getRecentByUserId(userId, limit);
return records.stream()
.map(this::convertToResponse)
.collect(Collectors.toList());
}
/**
* 转换为响应对象
*/
private EmotionRecordResponse convertToResponse(EmotionRecord record) {
EmotionRecordResponse response = new EmotionRecordResponse();
BeanUtils.copyProperties(record, response);
response.setId(record.getId());
if (record.getCreateTime() != null) {
response.setCreateTime(record.getCreateTime().format(DATE_TIME_FORMATTER));
}
if (record.getUpdateTime() != null) {
response.setUpdateTime(record.getUpdateTime().format(DATE_TIME_FORMATTER));
}
return response;
}
}
@@ -4,10 +4,13 @@ import com.emotion.dto.response.UserInfoResponse;
import com.emotion.exception.TokenException;
import com.emotion.service.AuthService;
import com.emotion.service.TokenService;
import com.emotion.util.TokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
/**
* 令牌服务实现类
*
@@ -20,15 +23,19 @@ public class TokenServiceImpl implements TokenService {
@Autowired
private AuthService authService;
@Autowired
private TokenUtil tokenUtil;
@Override
public UserInfoResponse getUserInfoByToken(String token) {
String userId = validateTokenAndGetUserId(token);
public UserInfoResponse getUserInfoByToken(HttpServletRequest request) {
String userId = validateTokenAndGetUserId(request);
return authService.getCurrentUserInfo(userId);
}
@Override
public String getUsernameByToken(String token) {
if (!StringUtils.hasText(token)) {
public String getUsernameByToken(HttpServletRequest request) {
String token = tokenUtil.extractToken(request);
if (!tokenUtil.isValidToken(token)) {
throw new TokenException("未提供访问令牌");
}
@@ -45,8 +52,9 @@ public class TokenServiceImpl implements TokenService {
}
@Override
public String validateTokenAndGetUserId(String token) {
if (!StringUtils.hasText(token)) {
public String validateTokenAndGetUserId(HttpServletRequest request) {
String token = tokenUtil.extractToken(request);
if (!tokenUtil.isValidToken(token)) {
throw new TokenException("未提供访问令牌");
}
@@ -61,4 +69,4 @@ public class TokenServiceImpl implements TokenService {
return userId;
}
}
}
@@ -1,5 +1,6 @@
package com.emotion.service.impl;
import com.emotion.dto.request.WebSocketRequest;
import com.emotion.dto.websocket.ChatRequest;
import com.emotion.dto.websocket.ConnectRequest;
import com.emotion.dto.websocket.WebSocketMessage;
@@ -13,6 +14,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.security.Principal;
import java.time.LocalDateTime;
@@ -48,64 +50,54 @@ public class WebSocketServiceImpl implements WebSocketService {
* 处理聊天消息
*/
@Override
public void handleChatMessage(ChatRequest request, String sessionId, Principal principal) {
public void handleChatMessage(WebSocketRequest webSocketRequest, String sessionId, Principal principal) {
try {
log.info("处理聊天消息: request={}, sessionId={}, principal={}", request, sessionId, principal);
log.info("处理聊天消息: request={}, sessionId={}, principal={}", webSocketRequest, sessionId, principal);
// 验证请求参数
if (request.getContent() == null || request.getContent().trim().isEmpty()) {
sendErrorMessage(request.getSenderId(), "消息内容不能为空");
if (webSocketRequest.getContent() == null || webSocketRequest.getContent().trim().isEmpty()) {
sendErrorMessage(getUserId(principal, sessionId), "消息内容不能为空");
return;
}
// 确定用户身份和类型
String userId = request.getSenderId();
WebSocketMessage.SenderType senderType = WebSocketMessage.SenderType.GUEST;
// 设置默认值
setWebSocketRequestDefaults(webSocketRequest, principal, sessionId);
if (principal != null) {
userId = principal.getName();
// 如果用户ID不是以guest_开头,说明是认证用户
if (!userId.startsWith("guest_")) {
senderType = WebSocketMessage.SenderType.USER;
}
}
log.info("确定用户身份: userId={}, senderType={}", webSocketRequest.getSenderId(),
webSocketRequest.getSenderType());
// 更新请求中的用户信息
request.setSenderId(userId);
request.setSenderType(senderType == WebSocketMessage.SenderType.USER ? ChatRequest.SenderType.USER
: ChatRequest.SenderType.GUEST);
log.info("确定用户身份: userId={}, senderType={}", userId, senderType);
// 转换请求对象
ChatRequest chatRequest = convertToChatRequest(webSocketRequest);
// 构建用户消息
WebSocketMessage userMessage = WebSocketMessage.builder()
.messageId(UUID.randomUUID().toString())
.conversationId(request.getConversationId())
.type(WebSocketMessage.MessageType.TEXT)
.content(request.getContent())
.senderId(userId)
.senderType(senderType)
.status(WebSocketMessage.MessageStatus.SENT)
.conversationId(chatRequest.getConversationId())
.type("TEXT")
.content(chatRequest.getContent())
.senderId(chatRequest.getSenderId())
.senderType(getSenderType(chatRequest.getSenderType()))
.status("SENT")
.createTime(LocalDateTime.now())
.build();
// 发送用户消息到会话
if (request.getConversationId() != null) {
messagingTemplate.convertAndSend("/topic/conversation/" + request.getConversationId(), userMessage);
if (chatRequest.getConversationId() != null) {
messagingTemplate.convertAndSend("/topic/conversation/" + chatRequest.getConversationId(), userMessage);
}
// 发送给用户私有队列
messagingTemplate.convertAndSendToUser(request.getSenderId(), "/queue/messages", userMessage);
messagingTemplate.convertAndSendToUser(chatRequest.getSenderId(), "/queue/messages", userMessage);
// 发送AI思考状态
sendAiThinkingMessage(request.getSenderId(), request.getConversationId());
sendAiThinkingMessage(chatRequest.getSenderId(), chatRequest.getConversationId());
// 异步调用AI服务
processAiResponse(request);
processAiResponse(chatRequest);
} catch (Exception e) {
log.error("处理聊天消息失败", e);
sendErrorMessage(request.getSenderId(), "消息处理失败,请稍后重试");
sendErrorMessage(getUserId(principal, sessionId), "消息处理失败,请稍后重试");
}
}
@@ -115,39 +107,27 @@ public class WebSocketServiceImpl implements WebSocketService {
@Override
public void handleUserConnect(ConnectRequest request, String sessionId, Principal principal) {
try {
String userId = request.getUserId();
boolean isAuthenticated = false;
// 优先从Principal获取认证用户信息
if (principal != null) {
userId = principal.getName();
// 检查是否是认证用户(不是访客)
isAuthenticated = !userId.startsWith("guest_");
}
// 如果还没有userId,生成访客ID
if (userId == null) {
userId = "guest_" + sessionId;
}
// 设置默认值
setConnectRequestDefaults(request, principal, sessionId);
log.info("用户连接WebSocket: userId={}, sessionId={}, authenticated={}",
userId, sessionId, isAuthenticated);
request.getUserId(), sessionId, isUserAuthenticated(request.getUserId()));
// 记录在线用户
onlineUsers.put(sessionId, userId);
onlineUsers.put(sessionId, request.getUserId());
// 发送连接成功消息
WebSocketMessage connectMessage = WebSocketMessage.builder()
.messageId(UUID.randomUUID().toString())
.type(WebSocketMessage.MessageType.CONNECTION)
.type("CONNECTION")
.content("连接成功")
.senderId("system")
.senderType(WebSocketMessage.SenderType.SYSTEM)
.status(WebSocketMessage.MessageStatus.SENT)
.senderType("SYSTEM")
.status("SENT")
.createTime(LocalDateTime.now())
.build();
messagingTemplate.convertAndSendToUser(userId, "/queue/messages", connectMessage);
messagingTemplate.convertAndSendToUser(request.getUserId(), "/queue/messages", connectMessage);
} catch (Exception e) {
log.error("处理用户连接失败", e);
@@ -182,11 +162,11 @@ public class WebSocketServiceImpl implements WebSocketService {
// 发送心跳响应
WebSocketMessage heartbeatMessage = WebSocketMessage.builder()
.messageId(UUID.randomUUID().toString())
.type(WebSocketMessage.MessageType.HEARTBEAT)
.type("HEARTBEAT")
.content("pong")
.senderId("system")
.senderType(WebSocketMessage.SenderType.SYSTEM)
.status(WebSocketMessage.MessageStatus.SENT)
.senderType("SYSTEM")
.status("SENT")
.createTime(LocalDateTime.now())
.build();
@@ -206,11 +186,11 @@ public class WebSocketServiceImpl implements WebSocketService {
WebSocketMessage thinkingMessage = WebSocketMessage.builder()
.messageId(UUID.randomUUID().toString())
.conversationId(conversationId)
.type(WebSocketMessage.MessageType.AI_THINKING)
.type("AI_THINKING")
.content("AI正在思考中...")
.senderId("ai")
.senderType(WebSocketMessage.SenderType.AI)
.status(WebSocketMessage.MessageStatus.SENT)
.senderType("AI")
.status("SENT")
.createTime(LocalDateTime.now())
.build();
@@ -246,7 +226,7 @@ public class WebSocketServiceImpl implements WebSocketService {
userMessage.setUserId(userId);
userMessage.setCreateBy(userId); // 设置创建人为当前用户
userMessage
.setUserType(request.getSenderType() == ChatRequest.SenderType.USER ? "registered" : "guest");
.setUserType("USER".equals(request.getSenderType()) ? "registered" : "guest");
userMessage.setContent(request.getContent());
userMessage.setType("text");
userMessage.setSender("user");
@@ -281,11 +261,11 @@ public class WebSocketServiceImpl implements WebSocketService {
private void sendErrorMessage(String userId, String errorContent) {
WebSocketMessage errorMessage = WebSocketMessage.builder()
.messageId(UUID.randomUUID().toString())
.type(WebSocketMessage.MessageType.ERROR)
.type("ERROR")
.content(errorContent)
.senderId("system")
.senderType(WebSocketMessage.SenderType.SYSTEM)
.status(WebSocketMessage.MessageStatus.SENT)
.senderType("SYSTEM")
.status("SENT")
.createTime(LocalDateTime.now())
.build();
@@ -309,7 +289,7 @@ public class WebSocketServiceImpl implements WebSocketService {
Conversation conversation = Conversation.builder()
.userId(userId)
.userType(request.getSenderType() == ChatRequest.SenderType.USER ? "registered" : "guest")
.userType("USER".equals(request.getSenderType()) ? "registered" : "guest")
.title("新对话")
.type("chat")
.conversationStatus("active")
@@ -341,7 +321,7 @@ public class WebSocketServiceImpl implements WebSocketService {
// 如果会话不存在,创建一个
conversation = Conversation.builder()
.userId(userId)
.userType(request.getSenderType() == ChatRequest.SenderType.USER ? "registered" : "guest")
.userType("USER".equals(request.getSenderType()) ? "registered" : "guest")
.title("对话")
.type("chat")
.conversationStatus("active")
@@ -453,11 +433,11 @@ public class WebSocketServiceImpl implements WebSocketService {
WebSocketMessage fallbackMessage = WebSocketMessage.builder()
.messageId(UUID.randomUUID().toString())
.conversationId(conversationId)
.type(WebSocketMessage.MessageType.TEXT)
.type("TEXT")
.content(aiReply)
.senderId("ai")
.senderType(WebSocketMessage.SenderType.AI)
.status(WebSocketMessage.MessageStatus.SENT)
.senderType("AI")
.status("SENT")
.createTime(LocalDateTime.now())
.build();
@@ -488,11 +468,11 @@ public class WebSocketServiceImpl implements WebSocketService {
WebSocketMessage aiMessage = WebSocketMessage.builder()
.messageId(UUID.randomUUID().toString())
.conversationId(conversationId)
.type(WebSocketMessage.MessageType.TEXT)
.type("TEXT")
.content(content)
.senderId("ai")
.senderType(WebSocketMessage.SenderType.AI)
.status(WebSocketMessage.MessageStatus.SENT)
.senderType("AI")
.status("SENT")
.createTime(LocalDateTime.now())
.build();
@@ -534,4 +514,95 @@ public class WebSocketServiceImpl implements WebSocketService {
log.debug("没有换行符,返回原始内容");
return new String[]{aiReply};
}
}
/**
* 设置WebSocket请求的默认值
*/
private void setWebSocketRequestDefaults(WebSocketRequest request, Principal principal, String sessionId) {
// 如果请求中没有发送者ID,尝试从Principal获取
if (request.getSenderId() == null && principal != null) {
request.setSenderId(principal.getName());
}
// 如果还是没有发送者ID,使用会话ID作为访客ID
if (request.getSenderId() == null) {
request.setSenderId("guest_" + sessionId);
request.setSenderType("GUEST");
}
// 设置时间戳
if (request.getTimestamp() == null) {
request.setTimestamp(System.currentTimeMillis());
}
}
/**
* 设置连接请求的默认值
*/
private void setConnectRequestDefaults(ConnectRequest request, Principal principal, String sessionId) {
// 优先从Principal获取认证用户信息
if (principal != null) {
request.setUserId(principal.getName());
}
// 如果还没有userId,生成访客ID
if (request.getUserId() == null) {
request.setUserId("guest_" + sessionId);
}
// 设置连接时间戳
if (request.getTimestamp() == null) {
request.setTimestamp(System.currentTimeMillis());
}
}
/**
* 获取用户ID
*/
private String getUserId(Principal principal, String sessionId) {
if (principal != null) {
return principal.getName();
}
return "guest_" + sessionId;
}
/**
* 判断用户是否已认证
*/
private boolean isUserAuthenticated(String userId) {
return userId != null && !userId.startsWith("guest_");
}
/**
* 获取发送者类型
*/
private String getSenderType(String senderType) {
if ("USER".equals(senderType)) {
return "USER";
} else if ("GUEST".equals(senderType)) {
return "GUEST";
} else if ("AI".equals(senderType)) {
return "AI";
} else if ("SYSTEM".equals(senderType)) {
return "SYSTEM";
}
return "USER";
}
/**
* 转换WebSocketRequest到ChatRequest
*
* @param webSocketRequest WebSocket请求对象
* @return ChatRequest对象
*/
private ChatRequest convertToChatRequest(WebSocketRequest webSocketRequest) {
return ChatRequest.builder()
.content(webSocketRequest.getContent())
.senderId(webSocketRequest.getSenderId())
.senderType(webSocketRequest.getSenderType())
.messageType(webSocketRequest.getMessageType())
.conversationId(webSocketRequest.getConversationId())
.timestamp(webSocketRequest.getTimestamp())
.build();
}
}