4.3 关注、取消关注和关注、粉丝列表
文章目录
设计Redis的key和Value开发关注、取关的业务开发Controller,接受关注取关请求修改主页的js增加获取关注,粉丝数量,是否关注的业务主页的Controller修改页面
关注、粉丝列表业务层表现层修改页面
# 关注、取消关注
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xwZ8AhZC-1646567007779)(D:\TyporaNotes\牛客网论坛项目\第三章图片\image-20220306104936732.png)]
设计Redis的key和Value
查询关注列表 查询某个用户关注的实体 传入这个需要查找的用户的userId,再传入关注列表的类型;使用有序集合,放入实体的id,和当前时间,方便后续显示关注时间等功能。查询粉丝列表 查询某个实体拥有的粉丝 传入这个实体的类型和id;使用有序集合,放入关注者的id,和当前时间,方便后续显示关注时间等功能。
private static final String PREFIX_FOLLOWEE = "followee:";
private static final String PREFIX_FOLLOWER = "follower:";
//某个用户关注的实体
//followee:userid:entityType -->zset(entityid,now)
public static String getFolloweeKey(int userId,int entityType)
{
return PREFIX_FOLLOWEE+userId+SPLIT+entityType;
}
//查询某个实体的粉丝列表
//follower:entityType:entityId -->zset(userId,now)
public static String getFollowerKey(int entityType,int entityId)
{
return PREFIX_FOLLOWER+entityType+SPLIT+entityId;
}
开发关注、取关的业务
因为需要设置两个key,启用Redis的业务操作 使用当前时间的ms
@Service
public class FollowService {
@Autowired
private RedisTemplate redisTemplate;
//关注 需要设置关注和粉丝 使用事务
public void follow(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);
//开始Redis事务
operations.multi();
operations.opsForZSet().add(followeeKey,entityId,System.currentTimeMillis());
operations.opsForZSet().add(followerKey,userId,System.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);
//开始Redis事务
operations.multi();
operations.opsForZSet().remove(followeeKey,entityId);
operations.opsForZSet().remove(followerKey,userId);
//提交事务
return operations.exec();
}
});
}
}
开发Controller,接受关注取关请求
当前用户关注某个实体
@Controller
public class FollowController {
@Autowired
FollowService followService;
//从登录的用户中获取User信息
@Autowired
HostHolder hostHolder;
//关注
@RequestMapping(value = "/follow",method = RequestMethod.POST)
@ResponseBody
public String follow(int entityType,int entityId){
User user = hostHolder.getUser();
followService.follow(user.getId(),entityType,entityId);
//返回JSON字符串
return CommunityUtil.getJSONString(0,"已关注!");
}
//取消关注
@RequestMapping(value = "/unfollow",method = RequestMethod.POST)
@ResponseBody
public String unfollow(int entityType,int entityId){
User user = hostHolder.getUser();
followService.unfollow(user.getId(),entityType,entityId);
//返回JSON字符串
return CommunityUtil.getJSONString(0,"已取消关注!");
}
}
修改主页的js
获取userId 使用隐藏框 然后获取按钮的前一个结点的值
$(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");
}
}
增加获取关注,粉丝数量,是否关注的业务
//查询关注的实体数量
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);
//查询当前key是否有分数就知道是否已经关注
return redisTemplate.opsForZSet().score(followeeKey,entityId)!=null;
}
主页的Controller
//关注数量
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);
修改页面
关注、粉丝列表
业务层
需要分页,因此需要传入分页的参数;
通过key使用时间倒叙查出目标id(即用户关注的人组成的集合);
遍历ids,通过id查到相应的user信息;
通过key和id查出相应的分数即创建时间,放入到map里;
// 查询某用户关注的人
public List
String followeeKey = RedisKeyUtil.getFolloweeKey(userId, ENTITY_TYPE_USER);
Set
if (targetIds == null) {
return null;
}
List
for (Integer targetId : targetIds) {
Map
User user = userService.queryUserById(targetId);
map.put("user", user);
Double score = redisTemplate.opsForZSet().score(followeeKey, targetId);
map.put("followTime", new Date(score.longValue()));
list.add(map);
}
return list;
}
// 查询某用户的粉丝
public List
String followerKey = RedisKeyUtil.getFollowerKey(ENTITY_TYPE_USER, userId);
Set
if (targetIds == null) {
return null;
}
List
for (Integer targetId : targetIds) {
Map
User user = userService.queryUserById(targetId);
map.put("user", user);
Double score = redisTemplate.opsForZSet().score(followerKey, targetId);
map.put("followTime", new Date(score.longValue()));
list.add(map);
}
return list;
}
表现层
首先向模板中保存该用户的用户信息,方便修改;设置分页参数 起始页和每页的条数;调用Service查询该用户的关注列表;遍历userList,获取该关注列表里的每一个用户的信息;需要判断登录的用户是否关注了列表里的其他用户,来显示未关注和已关注;
//查找该用户的关注列表
@RequestMapping(path = "/followees/{userId}", method = RequestMethod.GET)
public String getFollowees(@PathVariable("userId") int userId, Page page, Model model) {
//查询当前用户信息
User user = userService.queryUserById(userId);
if (user == null) {
throw new RuntimeException("该用户不存在!");
}
//向模板保存当前用户的信息
model.addAttribute("user", user);
//设置分页参数
page.setLimit(5);
page.setPath("/followees/" + userId);
page.setRows((int) followService.findFolloweeCount(userId, ENTITY_TYPE_USER));
//调用Service查询该用户的关注列表
List
if (userList != null) {
//遍历userList,获取该关注列表里的每一个用户的信息
for (Map
User u = (User) map.get("user");
map.put("hasFollowed", hasFollowed(u.getId()));
}
}
model.addAttribute("users", userList);
return "/site/followee";
}
//查看该用户的粉丝列表
@RequestMapping(path = "/followers/{userId}", method = RequestMethod.GET)
public String getFollowers(@PathVariable("userId") int userId, Page page, Model model) {
User user = userService.queryUserById(userId);
if (user == null) {
throw new RuntimeException("该用户不存在!");
}
model.addAttribute("user", user);
page.setLimit(5);
page.setPath("/followers/" + userId);
page.setRows((int) followService.findFollowerCount(ENTITY_TYPE_USER, userId));
List
if (userList != null) {
for (Map
User u = (User) map.get("user");
//判断当前登录的用户是否已经关注粉丝列表里其他人
map.put("hasFollowed", hasFollowed(u.getId()));
}
}
model.addAttribute("users", userList);
return "/site/follower";
}
//判断登录的用户是否关注了列表里的其他用户
private boolean hasFollowed(int userId) {
if (hostHolder.getUser() == null) {
return false;
}
return followService.hasFollowed(hostHolder.getUser().getId(), ENTITY_TYPE_USER, userId);
}
修改页面
1、修改关注和关注者请求,改为相应的请求,加拼上当前用户的id
2、遍历usersList集合,修改每一个用户的信息
```
用Excel制作自动考勤表,需要掌握哪些Excel函数?|教你十分钟做出来一个asp的增改删功能的网站