diff --git a/src/main/java/com/ai/da/controller/PortfolioController.java b/src/main/java/com/ai/da/controller/PortfolioController.java index 09e8bd39..c69c7485 100644 --- a/src/main/java/com/ai/da/controller/PortfolioController.java +++ b/src/main/java/com/ai/da/controller/PortfolioController.java @@ -1,12 +1,11 @@ package com.ai.da.controller; +import com.ai.da.common.config.exception.BusinessException; import com.ai.da.common.response.PageBaseResponse; import com.ai.da.common.response.Response; +import com.ai.da.mapper.primary.entity.Account; import com.ai.da.model.dto.*; -import com.ai.da.model.vo.CommentVO; -import com.ai.da.model.vo.PortfolioVO; -import com.ai.da.model.vo.UserLikeChooseVO; -import com.ai.da.model.vo.UserLikeGroupVO; +import com.ai.da.model.vo.*; import com.ai.da.service.PortfolioService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @@ -16,6 +15,7 @@ import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; import javax.validation.Valid; +import java.util.List; @Api(tags = "Portfolio模块") @Slf4j @@ -117,4 +117,31 @@ public class PortfolioController { public Response commentDelete(@Valid @RequestBody CommentDTO commentDTO) { return Response.success(portfolioService.commentDelete(commentDTO)); } + + @ApiOperation(value = "关注") + @GetMapping("/follow") + public Response follow(@RequestParam("followeeId") Long followeeId) { + portfolioService.follow(followeeId); + return Response.success(BusinessException.getMessageFromResource("subscription.success")); + } + + @ApiOperation(value = "取消关注") + @GetMapping("/cancelFollow") + public Response cancelFollow(@RequestParam("followeeId") Long followeeId) { + portfolioService.cancelFollow(followeeId); + return Response.success(BusinessException.getMessageFromResource("unsubscribe.success")); + } + + @ApiOperation(value = "获取关注列表") + @PostMapping("/getFolloweeList") + public Response> getFolloweeList(@Valid @RequestBody PageQueryBaseVo pageQueryBaseVo) { + return Response.success(portfolioService.getFolloweeList(pageQueryBaseVo)); + } + + @ApiOperation(value = "获取粉丝列表") + @PostMapping("/getFollowerList") + public Response> getFollowerList(@Valid @RequestBody PageQueryBaseVo pageQueryBaseVo) { + return Response.success(portfolioService.getFollowerList(pageQueryBaseVo)); + } + } diff --git a/src/main/java/com/ai/da/mapper/primary/UserFollowMapper.java b/src/main/java/com/ai/da/mapper/primary/UserFollowMapper.java new file mode 100644 index 00000000..77e2b6d8 --- /dev/null +++ b/src/main/java/com/ai/da/mapper/primary/UserFollowMapper.java @@ -0,0 +1,9 @@ +package com.ai.da.mapper.primary; + +import com.ai.da.common.config.mybatis.plus.CommonMapper; +import com.ai.da.mapper.primary.entity.UserFollow; + + +public interface UserFollowMapper extends CommonMapper { + +} diff --git a/src/main/java/com/ai/da/mapper/primary/entity/Notification.java b/src/main/java/com/ai/da/mapper/primary/entity/Notification.java index 2e743a8f..12242ad3 100644 --- a/src/main/java/com/ai/da/mapper/primary/entity/Notification.java +++ b/src/main/java/com/ai/da/mapper/primary/entity/Notification.java @@ -49,6 +49,12 @@ public class Notification extends BaseEntity{ public Notification() { } + public Notification(String type, Long senderId, Long receiverId) { + this.type = type; + this.senderId = senderId; + this.receiverId = receiverId; + } + public Notification(String type, Long senderId, Long receiverId, Long portfolioId) { this.type = type; this.senderId = senderId; diff --git a/src/main/java/com/ai/da/mapper/primary/entity/UserFollow.java b/src/main/java/com/ai/da/mapper/primary/entity/UserFollow.java new file mode 100644 index 00000000..82e7a810 --- /dev/null +++ b/src/main/java/com/ai/da/mapper/primary/entity/UserFollow.java @@ -0,0 +1,26 @@ +package com.ai.da.mapper.primary.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +@EqualsAndHashCode(callSuper = true) +@TableName("t_user_follow") +@Data +@AllArgsConstructor +@NoArgsConstructor +public class UserFollow extends BaseEntity{ + + /** + * 被关注者用户id + */ + private Long followeeId; + /** + * 关注者用户id + */ + private Long followerId; + + +} diff --git a/src/main/java/com/ai/da/model/vo/PortfolioVO.java b/src/main/java/com/ai/da/model/vo/PortfolioVO.java index c7c0a088..ee37c350 100644 --- a/src/main/java/com/ai/da/model/vo/PortfolioVO.java +++ b/src/main/java/com/ai/da/model/vo/PortfolioVO.java @@ -28,4 +28,6 @@ public class PortfolioVO extends Portfolio { private Integer selected; private Integer jumpable; + + private Integer isFollow; } diff --git a/src/main/java/com/ai/da/service/PortfolioService.java b/src/main/java/com/ai/da/service/PortfolioService.java index b809857c..00da09d7 100644 --- a/src/main/java/com/ai/da/service/PortfolioService.java +++ b/src/main/java/com/ai/da/service/PortfolioService.java @@ -1,14 +1,18 @@ package com.ai.da.service; import com.ai.da.common.response.PageBaseResponse; +import com.ai.da.mapper.primary.entity.Account; import com.ai.da.mapper.primary.entity.Portfolio; import com.ai.da.model.dto.*; import com.ai.da.model.vo.CommentVO; +import com.ai.da.model.vo.PageQueryBaseVo; import com.ai.da.model.vo.PortfolioVO; import com.ai.da.model.vo.UserLikeChooseVO; import com.baomidou.mybatisplus.extension.service.IService; import org.springframework.web.multipart.MultipartFile; +import java.util.List; + public interface PortfolioService extends IService { Boolean publish(MultipartFile canvas, String data); @@ -41,4 +45,12 @@ public interface PortfolioService extends IService { Boolean delete(Long id); Portfolio getByIdAll(Long originalPortfolioId); + + void follow(Long followeeId); + + void cancelFollow(Long followeeId); + + List getFolloweeList(PageQueryBaseVo pageQueryBaseVo); + + List getFollowerList(PageQueryBaseVo pageQueryBaseVo); } diff --git a/src/main/java/com/ai/da/service/impl/MessageCenterServiceImpl.java b/src/main/java/com/ai/da/service/impl/MessageCenterServiceImpl.java index 02c69ff8..cf7bb758 100644 --- a/src/main/java/com/ai/da/service/impl/MessageCenterServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/MessageCenterServiceImpl.java @@ -67,21 +67,33 @@ public class MessageCenterServiceImpl extends ServiceImpl getHistoryNotification(GetNotificationVO getNotificationVO) { + Long accountId = UserContext.getUserHolder().getId(); QueryWrapper queryWrapper = new QueryWrapper<>(); if (!StringUtils.isNullOrEmpty(getNotificationVO.getType())) { queryWrapper.eq("type", getNotificationVO.getType()); } - queryWrapper.eq("receiver_id", UserContext.getUserHolder().getId()); + if (!getNotificationVO.getType().equals("system")){ + queryWrapper.eq("receiver_id", accountId); + } Page notificationPage = baseMapper.selectPage(new Page<>(getNotificationVO.getPage(), getNotificationVO.getSize()), queryWrapper); + + List unreadSysNotificationIds = baseMapper.getUnreadSysNotification(accountId); IPage convert = notificationPage.convert(o -> { NotificationVO notificationVO = CopyUtil.copyObject(o, NotificationVO.class); Account account = accountService.getById(notificationVO.getSenderId()); notificationVO.setSenderUserName(account.getUserName()); notificationVO.setSenderUserAvatar(StringUtils.isNullOrEmpty(account.getAvatar()) ? null : minioUtil.getPreSignedUrl(account.getAvatar(), CommonConstant.MINIO_IMAGE_EXPIRE_TIME)); - notificationVO.setPortfolioName(portfolioService.getById(notificationVO.getPortfolioId()).getPortfolioName()); + notificationVO.setPortfolioName(Objects.isNull(notificationVO.getPortfolioId()) ? null : portfolioService.getById(notificationVO.getPortfolioId()).getPortfolioName()); + // 设置单个人 系统消息是否已读 + if (notificationVO.getType().equals("system")){ + if (unreadSysNotificationIds.contains(notificationVO.getId())){ + notificationVO.setIsRead(0); + }else { + notificationVO.setIsRead(1); + } + } return notificationVO; }); - return PageBaseResponse.success(convert); } @@ -195,7 +207,7 @@ public class MessageCenterServiceImpl extends ServiceImpl 0 ? totalSysCount - readCount : 0; } // 设置个人消息的已读状态 (允许一次已读多条个人消息) @@ -212,8 +224,8 @@ public class MessageCenterServiceImpl extends ServiceImpl implements PortfolioService { @@ -59,8 +60,8 @@ public class PortfolioServiceImpl extends ServiceImpl likedPortfolioIdList = redisUtil.getLikedPortfolios(userHolder.getId()); if (!CollectionUtils.isEmpty(likedPortfolioIdList)) { qw.lambda().in(Portfolio::getId, likedPortfolioIdList); - }else { + } else { return PageBaseResponse.success(new Page<>()); } } qw.lambda().orderByDesc(Portfolio::getUpdateDate); - IPage page = portfolioMapper.selectPage(new Page<>(query.getPage(), query.getSize()),qw); + IPage page = portfolioMapper.selectPage(new Page<>(query.getPage(), query.getSize()), qw); IPage convert = page.convert((Function) portfolio -> { if (portfolio != null) { PortfolioVO vo = CopyUtil.copyObject(portfolio, PortfolioVO.class); @@ -480,13 +483,23 @@ public class PortfolioServiceImpl extends ServiceImpl queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("followee_id", portfolio.getAccountId()).eq("follower_id", userHolder.getId()); + UserFollow userFollow = userFollowMapper.selectOne(queryWrapper); + if (Objects.isNull(userFollow)){ + vo.setIsFollow(0); + }else { + vo.setIsFollow(1); + } } redisUtil.increaseViewCount(portfolioDTO.getId()); vo.setViewNums(redisUtil.getViewCount(portfolioDTO.getId())); @@ -499,7 +512,7 @@ public class PortfolioServiceImpl extends ServiceImpl getSelectedQw = new QueryWrapper<>(); getSelectedQw.lambda().eq(UserLikeGroup::getAccountId, userHolder.getId()); @@ -519,7 +532,7 @@ public class PortfolioServiceImpl extends ServiceImpl userLikeGroups = userLikeGroupMapper.selectList(getSelectedQw); if (CollectionUtils.isEmpty(userLikeGroups)) { vo.setSelected(0); - }else { + } else { vo.setSelected(1); } } @@ -546,12 +559,12 @@ public class PortfolioServiceImpl extends ServiceImpl queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("followee_id", followeeId).eq("follower_id", accountId); + UserFollow userFollow = userFollowMapper.selectOne(queryWrapper); + if (!Objects.isNull(userFollow)) { + throw new BusinessException("you.have.already.followed.this.user", 1); + } + // 3、添加新follower到关注列表 + UserFollow newFollower = new UserFollow(followeeId, accountId); + newFollower.setCreateTime(LocalDateTime.now()); + userFollowMapper.insert(newFollower); + // 4、推送消息 + messageCenterService.prePushMessage(new Notification("follow", accountId, followeeId)); + } + + // 取消关注 + public void cancelFollow(Long followeeId){ + Long accountId = UserContext.getUserHolder().getId(); + // 1、确定是否关注了该用户 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("followee_id", followeeId).eq("follower_id", accountId); + UserFollow userFollow = userFollowMapper.selectOne(queryWrapper); + // 2、删除关注记录 + if (!Objects.isNull(userFollow)) { + userFollowMapper.deleteById(userFollow.getId()); + // 3、逻辑删除关注消息 + messageCenterService.cancelPushMessage("follow", accountId, followeeId, null, null); + }else { + throw new BusinessException("you.have.not.followed.the.current.user", 1); + } + } + + // 获取某个用户的关注列表 + public List getFolloweeList(PageQueryBaseVo pageQueryBaseVo){ + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("follower_id", UserContext.getUserHolder().getId()).select("followee_id"); + Page followPage = userFollowMapper.selectPage(new Page<>(pageQueryBaseVo.getPage(), pageQueryBaseVo.getSize()), queryWrapper); + + if (!followPage.getRecords().isEmpty()){ + List followeeIds = followPage.getRecords().stream().map(UserFollow::getFolloweeId).collect(Collectors.toList()); + return accountMapper.selectBatchIds(followeeIds); + } + return new ArrayList<>(); + } + + // 获取某个用户的粉丝列表 + public List getFollowerList(PageQueryBaseVo pageQueryBaseVo){ + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("followee_id", UserContext.getUserHolder().getId()).select("follower_id"); + Page followPage = userFollowMapper.selectPage(new Page<>(pageQueryBaseVo.getPage(), pageQueryBaseVo.getSize()), queryWrapper); + + if (!followPage.getRecords().isEmpty()){ + List followerIds = followPage.getRecords().stream().map(UserFollow::getFollowerId).collect(Collectors.toList()); + return accountMapper.selectBatchIds(followerIds); + } + return new ArrayList<>(); + } + } diff --git a/src/main/resources/messages_en.properties b/src/main/resources/messages_en.properties index aa36fa05..3e1f25ca 100644 --- a/src/main/resources/messages_en.properties +++ b/src/main/resources/messages_en.properties @@ -139,6 +139,11 @@ slogan.style.cannot.be.empty=Slogan style text cannot be empty. slogan.image.cannot.be.empty=Slogan image cannot be empty. questionnaire.filled.out=You have filled out the current questionnaire. user.has.no.account=The current user has no account! +you.cannot.follow.yourself=You cannot follow yourself +you.have.already.followed.this.user=You have already followed this user +subscription.success=Subscription Success +unsubscribe.success=Unsubscribe Success +you.have.not.followed.the.current.user=You have not followed the current user # 可能会报异常 # Informative: diff --git a/src/main/resources/messages_zh.properties b/src/main/resources/messages_zh.properties index e4bbeb87..043c8106 100644 --- a/src/main/resources/messages_zh.properties +++ b/src/main/resources/messages_zh.properties @@ -134,6 +134,11 @@ slogan.style.cannot.be.empty=标语风格文本不能为空。 slogan.image.cannot.be.empty=标语图片不能为空。 questionnaire.filled.out=您已填写过当前问卷。 user.has.no.account=当前用户没有账号。 +you.cannot.follow.yourself=您不能关注您自己 +you.have.already.followed.this.user=您已经关注当前用户 +subscription.success=关注成功 +unsubscribe.success=取消关注成功 +you.have.not.followed.the.current.user=您还未关注当前用户 # 可能会报异常 # Informative: