项目1在线交流平台-4. 使用radis高性能储存方案-4.开发个人主页-显示点赞信息-redis事务管理

本文介绍了如何使用Spring Boot和Redis进行个人主页的用户信息展示,包括点赞数量的实时更新。涉及DAO层的key生成、Service层的事务管理与点赞操作,以及Controller和View层的交互与模板更新。通过实例展示了点赞功能的异步请求处理和页面元素的动态调整。
摘要由CSDN通过智能技术生成

参考牛客网高级项目教程

狂神说Redis教程笔记

功能需求

在这里插入图片描述

  • 1.开发个人主页的个人信息模块,
    • 能够显示个人用户基本信息-头像,用户名-创建时间
    • 能够显示之前redis储存的点赞数量

1.dao层-redis的key生成工具更新

  • 由于要查询指定用户获取的点赞数量,需要设定新的key,value直接用String类型即可
/**
 * 某个用户收到的赞的key
 * @param userId    目标用户id
 * @return          针对特定用户的key
 */
public static String getUserLikeKey(int userId) {
    return PREFIX_USER_LIKE + SPLIT + userId;
}

2. Service层统计用户赞的数量

redis点赞事件-事务管理

  • 因点赞与统计要在一个事件中,故,更新之前点赞的函数,增加编程式事务处理
  • 因需要实体的作者id,如果再从数据库中查询,比较浪费性能,直接传入,上级调用时直接给就行
decrement(userLikeKey)
increment(userLikeKey)
/**
 * 添加赞或删除赞,根据当前用户点赞的状态来定
 * @param userId        当前访问用户id
 * @param entityType    访问的实体类型
 * @param entityId      访问的实体id
 */
public void like(int userId, int entityType, int entityId, int entityUserId) {
    redisTemplate.execute(new SessionCallback() {
        @Override
        public Object execute(RedisOperations operations) throws DataAccessException {
            String entityLikeKey = RedisLikeUtil.getEntityLikeKey(entityType, entityId);
            String userLikeKey = RedisLikeUtil.getUserLikeKey(entityUserId);
            // 在事务启动前查询
            Boolean isMember = operations.opsForSet().isMember(entityLikeKey, userId);
            // 启动事务
            operations.multi();
            if(isMember) {  // 已经点过赞了,再次点赞,就是取消赞
                operations.opsForSet().remove(entityLikeKey, userId);
                operations.opsForValue().decrement(userLikeKey);
            } else {
                operations.opsForSet().add(entityLikeKey, userId);
                operations.opsForValue().increment(userLikeKey);
            }
            return operations.exec();   // 提交事务
        }
    });
            
}

查询指定用户获取的赞的数量

  • redis的incr,decr默认是Integer类型
/**
 * 查询指定用户获取的点赞数量
 * @param userId    指定用户的id
 * @return          long类型个数
 */
public Long findUserLikeCount(int userId) {
    // 注意类型的转换-value为String类型,要转为int类型
    Integer count = (Integer)redisTemplate.opsForValue().get(RedisLikeUtil.getUserLikeKey(userId));
    return count == null ? 0 : count.intValue();
}

3. controller层处理请求

1.点赞异步请求更新

  • 由于要查询指定用户获取的赞,点赞事件请求中,将目标用户的id传入
public String like(int entityType, int entityId, int entityUserId) {
    // 用来封装信息的map
    Map<String, Object> map = new HashMap<>();
    // 权限-统一管理,先获取当前用户
    User user = hostHolder.getUser();
    // 点赞事件处理
    likeService.like(user.getId(), entityType, entityId, entityUserId);

2. 访问个人主页的请求

  • 可以访问不同用户的个人主页,只需要获取指定用户的id拼接进url即可
/**
 * 访问指定用户个人主页的请求
 * @param userId    指定的用户id
 * @param model
 * @return
 */
@RequestMapping(value = "/profile/{userId}", method = RequestMethod.GET)
public String getProfilePage(@RequestParam("userId") int userId, Model model) {
    // 先获取要访问的用户
    User user = userService.findUserById(userId);
    if(user == null) {
        throw new IllegalArgumentException("该用户不存在!");
    }
    // 将用户信息封装
    model.addAttribute("user", user);
    // 获取用户的点赞数量
    long likeCount = likeService.findUserLikeCount(userId);
    model.addAttribute("likeCount", likeCount);
    return "/site/profile";
}

4.View层模板处理

帖子详情页面点赞事件按钮更新

1.对帖子的点赞
<a href="javascript:;" class="text-primary" th:onclick="|like(this,1,${post.id},${user.id});|" >
2.对评论的点赞
<a href="javascript:;" class="text-primary" th:onclick="|like(this,2,${cvo.comment.id},${cvo.user.id});|">
3.对回复的点赞
<a href="javascript:;" class="text-primary" th:onclick="|like(this,2,${rvo.reply.id},${rvo.user.id});|">
js的更新js
  • 增加entityUserId参数
  • 并将entityUserId参数的值更新进JSON格式字符串中
function like(btn, entityType, entityId, entityUserId) {
    $.post(
        CONTEXT_PATH + "/like",
        {"entityType":entityType,"entityId":entityId,"entityUserId":entityUserId},
        function (data) {
            data = $.parseJSON(data);
            if(data.code == 0) {
                $(btn).children("i").text(data.likeCount);
                $(btn).children("b").text(data.likeStatus == 1 ? '已赞' : '赞');
            } else {
                alert(data.msg);
            }
        }
    );
}

个人主页模板设置

处理链接位置
1.主页中-个人信息
<a class="dropdown-item text-center" th:href="@{|/user/profile/${loginUser.id}|}">个人主页</a>
2.主页中-每个帖子的用户头像位置
<a th:href="@{|/user/profile/${map.user.id}|}">
   <img th:src="${map.user.headerUrl}" class="mr-4 rounded-circle" alt="用户头像" style="width:50px;height:50px;">
</a>
3.帖子详情页面
帖子的作者头像位置
<a th:href="@{|/user/profile/${user.id}|}">
   <img th:src="${user.headerUrl}" class="align-self-start mr-4 rounded-circle user-header" alt="用户头像" >
</a>
评论者的头像位置
<a th:href="@{|/user/profile/${cvo.user.id}|}">
   <img th:src="${cvo.user.headerUrl}" class="align-self-start mr-4 rounded-circle user-header" alt="用户头像" >
</a>
回复者的用户名位置
被回复者的用户名的位置
  • class="media pb-3 pt-3 mb-3 border-bottom"定义列表的样式
  • class="media-body"定义div标签段落的样式,这样和a标签形成左右分布的样式
  • class=“mt-0”, class=“mt-2” 分别定义每个div的垂直距离
<!-- 回复列表 -->
<ul class="list-unstyled mt-4 bg-gray p-3 font-size-12 text-muted">
   <!-- 循环遍历每条评论的所有回复 -->
   <li class="media pb-3 pt-3 mb-3 border-bottom" th:each="rvo:${cvo.replys}">
      <a th:href="@{|/user/profile/${rvo.user.id}|}">
         <img th:src="${rvo.user.headerUrl}" class="align-self-start mr-4 rounded-circle user-header" style="width:30px;height:30px;" alt="用户头像" >
      </a>
      <div class="media-body">
         <div th:if="${rvo.targetUser==null}">
            <div class="mt-0">
               <span th:text="${rvo.user.username}">寒江雪</span>

            </div>
            <div class="mt-2" th:utext="${rvo.reply.content}">
               这个是直播时间哈,觉得晚的话可以直接看之前的完整录播的~
            </div>
         </div>
         <div th:if="${rvo.targetUser!=null}">
            <div class="mt-0">
               <span th:text="${rvo.user.username}">Sissi</span>
            </div>
            <div class="mt-2">
               <a th:href="@{|/user/profile/${rvo.targetUser.id}|}">回复
                  <b class="text-info" th:text="|@${rvo.targetUser.username}|">寒江雪</b>
               </a>:
               <span th:utext="${rvo.reply.content}">回复的内容</span>
            </div>
         </div>

显示效果如下四个位置均可以链接到指定用户的个人主页:

在这里插入图片描述

处理个人主页模板
<li class="nav-item">
   <a class="nav-link active" th:href="@{|user/profile/${user.id}}|">个人信息</a>
</li>
<!-- 个人信息 -->
<div class="media mt-5">
   <img th:src="${user.headerUrl}" class="align-self-start mr-4 rounded-circle" alt="用户头像" style="width:50px;">
   <div class="media-body">
      <h5 class="mt-0 text-warning">
         <span th:utext="user.username">nowcoder</span>
         <button type="button" class="btn btn-info btn-sm float-right mr-5 follow-btn">关注TA</button>
      </h5>
      <div class="text-muted mt-3">
         <span>注册于
            <i class="text-muted" th:text="${#dates.format(user.createTime, 'yyyy-MM-dd HH:mm:ss')}">2015-06-12 15:20:12</i></span>
      </div>
      <div class="text-muted mt-3 mb-5">
         <span>关注了 <a class="text-primary" href="followee.html">5</a></span>
         <span class="ml-4">关注者 <a class="text-primary" href="follower.html">123</a></span>
         <span class="ml-4">获得了 <i class="text-danger" th:text="${likeCount}">87</i> 个赞</span>
      </div>
   </div>
</div>

测试结果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值