牛客网后端项目实战(二十八):收到的赞


• 重构点赞功能

  • 以用户为key,记录点赞数量
  • increment(key),decrement(key)

• 开发个人主页

  • 以用户为key,查询点赞数量
    在这里插入图片描述

收到的赞(重构点赞功能)

Servece层

1、增加一个Key,根据用户 userId 记录点赞数量。为了避免去数据库查用户收到的赞

// Redis Key 工具不用交给容器管理
public class RedisKeyUtil {

    private static final String SPLIT = ":";
  	...
    private static final String PREFIX_USER_LIKE = "like:user";

    // 某个用户的赞
    // like:user:userId -> int
    public static String getUserLikeKey(int userId) {
        return PREFIX_USER_LIKE + SPLIT + userId;
    }

2、重构点赞功能。
执行点赞操作时,前端界面同时传递 实体(帖子/回复) 的用户Id 给业务层,若是点赞操作,业务层在点赞的同时,会把实体用户Id 键对应的值+1;反之,则-1。

使用編程式事务,调用 redisTemplate.execute()方法,里面传递 SessionCallback() 接口的匿名实现,接口内要实现 execute() 方法,RedisOperations operations 是执行命令的对象

事务过程中的所有命令被放在队列里,提交后才执行,所以 like方法的 查询要放在事务之外。

@Service
public class LikeService {

    @Autowired
    private RedisTemplate redisTemplate;

    // 点赞
    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 = RedisKeyUtil.getEntityLikeKey(entityType, entityId);   // 生成实体对应的key
                String userLikeKey = RedisKeyUtil.getUserLikeKey(entityUserId); // 实体用户Id对应的Key
				
				// 查询操作要放在事务外
                boolean isMember = operations.opsForSet().isMember(entityLikeKey, userId);  // 判断 userId是否在 entityLikeKey 集合里

                operations.multi(); // 启用事务
                // 查询操作不能放在里面

                if (isMember) {
                    operations.opsForSet().remove(entityLikeKey, userId); // 若已存在,说明已经点过赞,将uerId从集合中移除(取消赞)
                    operations.opsForValue().decrement(userLikeKey);
                } else {
                    operations.opsForSet().add(entityLikeKey, userId); // 没点过赞,所以添加到集合中
                    operations.opsForValue().increment(userLikeKey);
                }

                return operations.exec(); // 提交事务
            }
        });
    }
    // 查询某个用户获得的赞
    public int findUserLikeCount(int userId) {
        String userLikeKey = RedisKeyUtil.getUserLikeKey(userId);
        Integer count = (Integer) redisTemplate.opsForValue().get(userLikeKey); // 返回的是Object类型所以要强转
        return count == null ? 0 : count.intValue();
    }

Controller层

写在了 UserController 类里面的 个人主页 方法

package com.nowcoder.community.controller;

@Controller
@RequestMapping("/user")
public class UserController implements CommunityConstant {
    // 个人主页
    @RequestMapping(path = "/profile/{userId}", method = RequestMethod.GET)
    public String getProfilePage(@PathVariable("userId") int userId, Model model) {
        User user = userService.findUserById(userId);
        if (user == null) {
            throw new RuntimeException("该用户不存在!");
        }

        // 用户
        model.addAttribute("user", user);
        // 点赞数量
        int likeCount = likeService.findUserLikeCount(userId);
        model.addAttribute("likeCount", likeCount);
        
        return "/site/profile";
    }
}

前端

首页
所有的用户头像都添加一个超链接跳转到个人主页上

						<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>

帖子详情页
重构点赞操作,把 实体用户id传给业务层

									<a href="javascript:;" th:onclick="|like(this,1,${post.id},${post.userId});|" class="text-primary">
										<b th:text="${likeStatus==1?'已赞':'赞'}">赞</b> <i th:text="${likeCount}">11</i>
									</a>
// discuss.js
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);
            }
        }
    );
}

个人主页 profile.html
1)修改静态资源,重用 头部
2)显示个人信息:用户头像、用户名、注册时间、收到的赞

				<!-- 个人信息 -->
				<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>
							<input type="hidden" id="entityId" th:value="${user.id}">
							<button type="button" th:class="|btn ${hasFollowed?'btn-secondary':'btn-info'} btn-sm float-right mr-5 follow-btn|"
									th:text="${hasFollowed?'已关注':'关注TA'}" th:if="${loginUser!=null&&loginUser.id!=user.id}">关注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" th:href="@{|/followees/${user.id}|}" th:text="${followeeCount}">5</a> 人</span>
							<span class="ml-4">关注者 <a class="text-primary" th:href="@{|/followers/${user.id}|}" th:text="${followerCount}">123</a> 人</span>
							<span class="ml-4">获得了 <i class="text-danger" th:text="${likeCount}">87</i> 个赞</span>
						</div>
					</div>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值