• Welcome to the world's largest Chinese hacker forum

    Welcome to the world's largest Chinese hacker forum, our forum registration is open! You can now register for technical communication with us, this is a free and open to the world of the BBS, we founded the purpose for the study of network security, please don't release business of black/grey, or on the BBS posts, to seek help hacker if violations, we will permanently frozen your IP and account, thank you for your cooperation. Hacker attack and defense cracking or network Security

    business please click here: Creation Security  From CNHACKTEAM

Recommended Posts

关注

需求

开发关注、取消关注功能。

统计用户的关注数、粉丝数。

关注

若A关注了b,则A是B的追随者(粉丝),B是A的追随者(目标)。

关注的目标可以是用户、帖子、题目等,在实现时将这些目标抽象为实体。

修改RedisKeyUtil

public class RedisKeyUtil {

私有静态最终字符串SPLIT=" :

私有静态最终字符串PREFIX _ ENTITY _ LIKE=' LIKE : ENTITY ';

private static final String PREFIX _ USER _ LIKE=' LIKE : USER ';

私有静态最终字符串PREFIX _ FOLLOWEE=' followee

私有静态最终字符串前缀_跟随者='跟随者

//某个实体的赞

//like :实体:实体类型:实体id-set(userId)

公共静态字符串getEntityLikeKey(int entityType,int entityId) {

返回PREFIX _ ENTITY _ LIKE拆分实体类型拆分实体id;

}

//某个用户的赞

//like:user:userId - int

公共静态字符串getuserlikkey(int userId){

返回前缀_用户_喜欢拆分使用者辩证码

}

//某个用户关注的实体

//这里实体的可以为用户,帖子等

//followeee : userid :实体类型-zset(entityId,now)

公共静态字符串getFolloweeKey(int userId,int entityType) {

return PREFIX _ follow eee SPLIT userId SPLIT实体类型;

}

//某个实体拥有的粉丝

//follower :实体类型:实体id-zset(userId,现在)

公共静态字符串getFollowerKey(int entityType,int entityId) {

return PREFIX _ FOLLOWER拆分实体类型拆分实体id;

}

}

编写业务层逻辑后续服务

@服务

公共类关注服务{

@自动连线

私有redistemp

public void follow(int userId,int entityType,int entityId) {

redis模板。执行(新会话回调(){

@覆盖

公共对象执行(再操作操作)引发DataAccessException {

string followee key=rediskeyutil。getfollowee key(userId,实体类型);

字符串跟随键=rediskeyutil。getfollowerkey(实体类型,entityId);

运营。multi();

opsForZSet().add(followeeKey,entityId,system。当前时间毫秒());

opsForZSet().添加(关注密钥、用户Id、系统

m.currentTimeMillis()); return operations.exec(); } }); } public void unfollow(int userId, int entityType, int entityId) { redisTemplate.execute(new SessionCallback() { @Override public Object execute(RedisOperations operations) throws DataAccessException { String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType); String followerKey = RedisKeyUtil.getFollowerKey(entityType, entityId); operations.multi(); operations.opsForZSet().remove(followeeKey, entityId); operations.opsForZSet().remove(followerKey, userId); return operations.exec(); } }); } // 查询关注的实体的数量 public long findFolloweeCount(int userId, int entityType) { String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType); return redisTemplate.opsForZSet().zCard(followeeKey); } // 查询实体的粉丝的数量 public long findFollowerCount(int entityType, int entityId) { String followerKey = RedisKeyUtil.getFollowerKey(entityType, entityId); return redisTemplate.opsForZSet().zCard(followerKey); } // 查询当前用户是否已关注该实体 public boolean hasFollowed(int userId, int entityType, int entityId) { String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType); return redisTemplate.opsForZSet().score(followeeKey, entityId) != null; } }
  1. 编写表现层逻辑
package com.nowcoder.community.controller;
@Controller
public class FollowController {
    @Autowired
    private FollowService followService;
    @Autowired
    private HostHolder hostHolder;
    @RequestMapping(path = "/follow", method = RequestMethod.POST)
    @ResponseBody
    public String follow(int entityType, int entityId) {
        User user = hostHolder.getUser();
        followService.follow(user.getId(), entityType, entityId);
        return CommunityUtil.getJSONString(0, "已关注!");
    }
    @RequestMapping(path = "/unfollow", method = RequestMethod.POST)
    @ResponseBody
    public String unfollow(int entityType, int entityId) {
        User user = hostHolder.getUser();
        followService.unfollow(user.getId(), entityType, entityId);
        return CommunityUtil.getJSONString(0, "已取消关注!");
    }
}

修改UserController的个人页面请求

 @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);
        // 关注数量
        long followeeCount = followService.findFolloweeCount(userId, ENTITY_TYPE_USER);
        model.addAttribute("followeeCount", followeeCount);
        // 粉丝数量
        long followerCount = followService.findFollowerCount(ENTITY_TYPE_USER, userId);
        model.addAttribute("followerCount", followerCount);
        // 是否已关注
        boolean hasFollowed = false;
        if (hostHolder.getUser() != null) {
            hasFollowed = followService.hasFollowed(hostHolder.getUser().getId(), ENTITY_TYPE_USER, userId);
        }
        model.addAttribute("hasFollowed", hasFollowed);
        return "/site/profile";
    }

接下来去处理静态页面,关注采用的是异步的方式 所以先编写对应的js

$(function(){
	$(".follow-btn").click(follow);
});
function follow() {
	var btn = this;
	if($(btn).hasClass("btn-info")) {
		// 关注TA
		$.post(
		    CONTEXT_PATH + "/follow",
		    {"entityType":3,"entityId":$(btn).prev().val()},
		    function(data) {
		        data = $.parseJSON(data);
		        if(data.code == 0) {
                    window.location.reload();
		        } else {
                    alert(data.msg);
		        }
		    }
		);
		// $(btn).text("已关注").removeClass("btn-info").addClass("btn-secondary");
	} else {
		// 取消关注
		$.post(
		    CONTEXT_PATH + "/unfollow",
		    {"entityType":3,"entityId":$(btn).prev().val()},
		    function(data) {
		        data = $.parseJSON(data);
		        if(data.code == 0) {
                    window.location.reload();
		        } else {
                    alert(data.msg);
		        }
		    }
		);
		//$(btn).text("关注TA").removeClass("btn-secondary").addClass("btn-info");
	}
}
  1. 修改个人主页html profile.html 84行
<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" href="followee.html" th:text="${followeeCount}">5</a> 人</span>
            <span class="ml-4">关注者 <a class="text-primary" href="follower.html" th:text="${followerCount}">123</a> 人</span>
            <span class="ml-4">获得了 <i class="text-danger" th:text="${likeCount}">87</i> 个赞</span>
        </div>
    </div>
</div>
</div>
</div>

okl

Link to comment
Share on other sites