19.圈子互动

圈子互动

点赞、喜欢、评论等均可理解为用户对动态的互动。

mongodb中的数据

  • 在动态详情Movement表中,加入喜欢,点赞,评论数量:减少数据库访问压力
    • 互动操作的时候,不要忘记对上面的字段进行维护
  • 圈子互动的表 comment
  • 互动完成(点赞,喜欢):不仅要将数据保存到mongo中,需要记录到redis中
  • 页面查询圈子列表时,可以从redis中判断是否有点赞,和喜欢历史

二、环境搭建

在动态详情表中补充字段

@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(collection = "movement")
public class Movement implements java.io.Serializable {

    private ObjectId id; //主键id
    //redis实现,使用Mongodb实现
    private Long pid; //Long类型,用于推荐系统的模型(自动增长)
    private Long created; //发布时间
    private Long userId;
    private String textContent; //文字
    private List<String> medias; //媒体数据,图片或小视频 url
    private String longitude; //经度
    private String latitude; //纬度
    private String locationName; //位置名称
    private Integer state = 0;//状态 0:未审(默认),1:通过,2:驳回

    //补充字段
    private Integer likeCount = 0; //点赞数
    private Integer commentCount = 0; //评论数
    private Integer loveCount = 0; //喜欢数
    
    //根据评论类型,获取对应的互动数量
    public Integer statisCount(Integer commentType) {
        if (commentType == CommentType.LIKE.getType()) {
            return this.likeCount;
        } else if (commentType == CommentType.COMMENT.getType()) {
            return this.commentCount;
        } else {
            return loveCount;
        }
    }
}

实体类

Comment

package com.tanhua.domain.mongo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.bson.types.ObjectId;
import org.springframework.data.mongodb.core.mapping.Document;

/**
 * 圈子互动表(点赞,评论,喜欢)
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(collection = "comment")
public class Comment implements java.io.Serializable{
    
    private ObjectId id;
    private ObjectId publishId;    //发布id
    private Integer commentType;   //评论类型,1-点赞,2-评论,3-喜欢
    private String content;        //评论内容  
    private Long userId;           //评论人   
    private Long publishUserId;    //被评论人ID
    private Long created; 		   //发表时间
    private Integer likeCount = 0; //当前评论的点赞数
    
}

vo

@Data
@NoArgsConstructor
@AllArgsConstructor
public class CommentVo implements Serializable {

    private String id; //评论id
    private String avatar; //头像
    private String nickname; //昵称


    private String content; //评论
    private String createDate; //评论时间
    private Integer likeCount; //点赞数
    private Integer hasLiked; //是否点赞(1是,0否)

    public static CommentVo init(UserInfo userInfo, Comment item) {
        CommentVo vo = new CommentVo();
        BeanUtils.copyProperties(userInfo, vo);
        BeanUtils.copyProperties(item, vo);
        vo.setHasLiked(0);
        Date date = new Date(item.getCreated());
        vo.setCreateDate(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date));
        vo.setId(item.getId().toHexString());
        return vo;
    }
}

CommentType枚举

/**
 * 评论类型:1-点赞,2-评论,3-喜欢
 */
public enum CommentType {

    LIKE(1), COMMENT(2), LOVE(3);

    int type;

    CommentType(int type) {
        this.type = type;
    }

    public int getType() {
        return type;
    }
}

api接口

public interface CommentApi {
    
}

api实现类

@DubboService
public class CommentApiImpl implements CommentApi {

    @Autowired
    private MongoTemplate mongoTemplate;
}

三、动态评论

功能包括:查询评论列表,发布评论,对评论点赞和取消点赞。

1. 发布评论

Controller

 /**
     * 对动态发布评论:
     * 请求路径:/comments
     * 请求方式:post
     * 请求参数:movementId(动态id,string),comment(评论内容,string)
     *响应数据:null
     */
    @PostMapping
    public ResponseEntity postCommen(@RequestBody Map map){

        String movementId = (String) map.get("movementId");
        String comment = (String) map.get("comment");

        commentService.postCommon(movementId,comment);
        return ResponseEntity.ok(null);
    }

Service


    /**
     *对动态发布评论
     * 就是要向数据库添加一条评论的数据,所有先用对象封装数据,然后调用api保存数据
     */

    public void postCommon(String movementId, String text) {

        //1.封装数据
        /**
         *             private ObjectId publishId;    //要评论的动态id
         *             private Integer commentType;   //评论类型,1-点赞,2-评论,3-喜欢
         *             private String content;        //评论内容
         *             private Long userId;           //评论人的id
         *             private Long publishUserId;    //被评论人ID
         *             private Long created; 		   //发表时间
         *             private Integer likeCount = 0; //当前评论的点赞数
        */

        //1.封装数据
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(movementId));//动态id
        comment.setCommentType(CommentType.COMMENT.getType());//评论
        comment.setContent(text);//评论的内容
        comment.setUserId(ThreadLocalUtils.getUserId());//评论人的id
        comment.setCreated(System.currentTimeMillis());
        //被评论人的id留到api层再封装
        //2.调用api保存数据
        Integer integer = commentApi.postCommen(comment);


    }

api层

 /**
     *
     * 发布评论
     */
    public Integer postCommen(Comment comment) {

        //1.接收的comment对象还没有被评论人的用户id

        //1.1先根据动态id获取动态详情,再在动态详情里获取被评论人的用户id,最后封装到comment里
        ObjectId publishId = comment.getPublishId();
        Movement movement = mongoTemplate.findById(publishId, Movement.class);
        comment.setPublishUserId(movement.getUserId());

        //1.2保存comment到数据库
        mongoTemplate.save(comment);

        //2.更新动态详情表里面的喜欢、评论、点赞等字段的数据,并获取更新后的数据

        //2.1创建Criteria对象,设置查询的条件,根据动态id查询
        Criteria criteria = Criteria.where("id").is(comment.getPublishId());
        Query query = Query.query(criteria);

        //2.2设置要更新的字段
        Update update = new Update();
        //2.3判断当前要处理的评论类型
        if(comment.getCommentType() == CommentType.LIKE.getType()){
            update.inc("likeCount",1);
        }else if(comment.getCommentType() == CommentType.COMMENT.getType()){
            update.inc("commentCount",1);
        }else{
            update.inc("loveCount", 1);
        }

        FindAndModifyOptions options = new FindAndModifyOptions();
        options.returnNew(true);//获取更新后的数据


        Movement modify = mongoTemplate.findAndModify(query, update, options, Movement.class);

        Integer count = modify.statisCount(comment.getCommentType());
        return count;
    }

2.分页列表查询评论

controller


    /**
     * 分页查询评论:
     *  * 请求路径:/comments
     *      * 请求方式:get
     *      * 请求参数:movementId(动态id),page(当前页),pageSize(每页展示数)
     *      *响应数据:PageResult
     */

    @GetMapping
    public ResponseEntity  lookComments(String movementId,
                                        @RequestParam(defaultValue = "1") Integer page,
                                        @RequestParam(defaultValue = "10") Integer pageSize){
       PageResult pageResult = commentService.lookComments(movementId,page,pageSize);
       return ResponseEntity.ok(pageResult);
    }

Service


    /**
     *
     *查看评论列表
     */
    public PageResult lookComments(String movementId, Integer page, Integer pageSize) {

        //1.调用api查询评论comments集合
        List<Comment> comments = commentApi.lookComments(movementId, page, pageSize, CommentType.COMMENT.getType());
        //2.判断集合是否为空,为空则直接new PageResult返回
        if(CollUtil.isEmpty(comments)){
          return   new PageResult();
        }
        //3.获取评论人的id,查询评论人的用户详情
        List<Long> userIds = CollUtil.getFieldValues(comments, "userId", Long.class);
        Map<Long, UserInfo> userInfoMap = userInfoApi.batchQueryUserInfo(userIds, null);
        //4.遍历评论集合,一个comment对象就构造一个vo对象
        List<CommentVo> commentVos = new ArrayList<>();

        for (Comment comment : comments) {
            Long id = comment.getUserId();
            UserInfo userInfo = userInfoMap.get(id);
            if(userInfo != null){
                CommentVo commentVo = CommentVo.init(userInfo, comment);
                commentVos.add(commentVo);
            }
        }
        //5.构造返回值
        PageResult pageResult = new PageResult(page,pageSize,0,commentVos);
        return pageResult;

    }


api



    /**
     *
     * 查看评论列表
     */
    public List<Comment> lookComments(String movementId, Integer page, Integer pageSize, int type) {
        //1.创建Criteria对象,设置查询条件,根据动态id和评论类型查询
        //注意,参数类型保持一致,条件有两个
        Criteria criteria =  Criteria.where("publishId").is(new ObjectId(movementId)).and("commentType").is(type);

        //2.根据criteria创建query对象
        Query query = Query.query(criteria);
        query.skip(( page - 1) * pageSize ).limit(pageSize).with(Sort.by(Sort.Order.desc("created")));

        List<Comment> comments = mongoTemplate.find(query, Comment.class);

        return comments;
    }

3.动态点赞

MovementController

/**
     * 动态点赞:
     * 请求路径:/movements/:id/like
     * 请求方式:get
     * 请求参数:路径参数id,动态id
     * 响应数据:	integer
     */
    @GetMapping({"/{id}/like"})
    public ResponseEntity like(@PathVariable("id") String id){
       Integer integer = commentService.like(id);
       return ResponseEntity.ok(integer);
    }

CommentService


    /**
     * 动态点赞
    **/
    public Integer like(String movementId) {

        //1.判断用户是否点赞过,如果有,抛出一个异常
        Boolean result = commentApi.isLike(ThreadLocalUtils.getUserId(), movementId,CommentType.LIKE);
        //2.true代表点赞过
        if(result){
            throw new BusinessException(ErrorResult.likeError());
        }

        //3.创建comment对象封装数据,调用api保存数据
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(movementId));//动态id
        comment.setCommentType(CommentType.LIKE.getType());
        comment.setUserId(ThreadLocalUtils.getUserId());//当前操作的用户id
        comment.setCreated(System.currentTimeMillis());

        Integer count = commentApi.postCommen(comment);

        //4.把点赞状态,缓存到Redis
        //存的value是hash值
        String key = Constants.MOVEMENTS_INTERACT_KEY +movementId;
        String hashKey = Constants.MOVEMENT_LIKE_HASHKEY + ThreadLocalUtils.getUserId();
        redisTemplate.opsForHash().put(key, hashKey, "1");

        return count;
    }

api

 /**
     *查看comment表是否有数据,取消点赞
     */
    public Boolean isLike(Long userId, String movementId, CommentType commentType) {
        Criteria criteria = Criteria.where("userId").is(userId)
                .and("publishId").is(new ObjectId(movementId))
                .and("commentType").is(commentType.getType());
        Query query = Query.query(criteria);
        boolean result = mongoTemplate.exists(query, Comment.class);

        return result;
    }




4.取消点赞

MovementController

  /**取消点赞:
     * 请求路径:/movements/:id/dislike
     * 请求方式:get
     * 请求参数:路径参数id,动态id
     * 响应数据:    Integer
     */
    @GetMapping("/{id}/dislike")
    public ResponseEntity disLike(@PathVariable("id") String id){
        Integer count = commentService.disLikeComment(id);
        return ResponseEntity.ok(count);
    }

CommentService



    /**
     *取消点赞
     */
    public Integer disLikeComment(String movementId) {

        //1.判断用户是否已经点赞过
        Boolean result = commentApi.isLike(ThreadLocalUtils.getUserId(),movementId,CommentType.LIKE);
        //2.如果没点赞过,抛出一个异常
        if(!result){
            //true代表点赞过
            throw new BusinessException(ErrorResult.disLikeError());
        }
        //3.封装要删除的数据,调用api删除
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(movementId));
        comment.setUserId(ThreadLocalUtils.getUserId());
        comment.setCommentType(CommentType.LIKE.getType());
        comment.setCreated(System.currentTimeMillis());

        Integer count = commentApi.delete(comment);

        //4.删除redis缓存的点赞状态

        String key = Constants.MOVEMENTS_INTERACT_KEY + movementId;
        String hashKey = Constants.MOVEMENT_LIKE_HASHKEY + ThreadLocalUtils.getUserId();

        redisTemplate.opsForHash().delete(key, hashKey);

        return count;
    }

5.动态喜欢

Controller


    /**
     * 动态喜欢:
     * 请求路径:/movements/:id/love
     * 请求方式:get
     * 请求参数:路径参数id(动态id)
     * 响应数据:    Integer
     */

    @GetMapping("/{id}/love")
    public ResponseEntity loveMovement(@PathVariable("id") String movementId){
       Integer count =  commentService.saveLoveMovement(movementId);
       return ResponseEntity.ok(count);
    }

Service

/**
     *
     * 动态喜欢
     */
    public Integer saveLoveMovement(String movementId) {
        //1.判断用户是否点过喜欢,点过之后就不可以再点了;其实际就是查询comment表有没有数据
       Boolean result = commentApi.isLike(ThreadLocalUtils.getUserId(),movementId,CommentType.LOVE);

        //2.用户点过喜欢,抛出一个异常

        if(result){
            //true代表用户已喜欢
            throw new BusinessException(ErrorResult.loveError());
        }
        //3.封装数据,调用api保存数据

        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(movementId));
        comment.setCommentType(CommentType.LOVE.getType());
        comment.setUserId(ThreadLocalUtils.getUserId());
        comment.setCreated(System.currentTimeMillis());

        Integer count = commentApi.postCommen(comment);
        //4.把喜欢的状态缓存至redis
        String key = Constants.MOVEMENTS_INTERACT_KEY + comment.getPublishId();
        String hashKey = Constants.MOVEMENT_LOVE_HASHKEY + ThreadLocalUtils.getUserId();
        redisTemplate.opsForHash().hasKey(key, hashKey);


        return count;
    }


6.取消喜欢动态

Controller

 /**
     * 动态取消喜欢:
     * 请求路径:/movements/:id/unlove
     * 请求方式:get
     * 请求参数:路径参数id(动态Id)
     * 响应数据:    Integer
     */

    @GetMapping("/{id}/unlove")
    public  ResponseEntity unLove(@PathVariable("id") String movementId){
      Integer count =  commentService.unLOve(movementId);

      return ResponseEntity.ok(count);
    }

Service


    /**
     *取消喜欢
     */
    public Integer unLOve(String movementId) {
    //2.判断用户有没有喜欢过,没有喜欢过不能取消喜欢
        Boolean result = commentApi.isLike(ThreadLocalUtils.getUserId(), movementId, CommentType.LOVE);

        if(!result){
            throw new BusinessException(ErrorResult.disloveError());
        }

        //2.封装要删除的数据,调用api删除数据
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(movementId));
        comment.setCommentType(CommentType.LOVE.getType());
        comment.setUserId(ThreadLocalUtils.getUserId());
        comment.setCreated(System.currentTimeMillis());
        Integer count = commentApi.delete(comment);
        //3.删除redis缓存的喜欢状态
        String key = Constants.MOVEMENTS_INTERACT_KEY + comment.getPublishId();
        String hashKey = Constants.MOVEMENT_LOVE_HASHKEY + ThreadLocalUtils.getUserId();

        redisTemplate.opsForHash().delete(key, hashKey);

        return count;
    }

posted @ 2022-10-30 12:09  给我手牵你走  阅读(51)  评论(0编辑  收藏  举报