前言
架构
- 首先我讲一下整体的架构(假装很厉害吧);
- JedisAdapter用来做Redis的适配,我们对一些redis命令进行封装;
- RedisKeyUtil 是用来记录redis中的key的;比如我们通过一个实体类别+实体id为key,然后就可以找到这个实体的关注者;相同的,我们可以通过userId+ 实体类别,就可以找到用户在这个方向关注什么了;
- 然后我们想一下,一个关注事件发生后,会怎么样呢,是不是会发生私信事件,所以我们就可以在消息处理部分加一个handler,然后关注时,发出这样的消息;
- 然后我们想一下,加上关注后,首先是我们关注了谁,关注了那些问题,事件,什么之类的,这些就可以通过userId+实体类别取出;然后是关注者,不管是问题还是人,都可以通过实体类别+实体id 找到它的关注者;还有就是当我们关注或者取消关注时,页面会发生变化,所以关注的代码是最多的,因为牵涉面最多,前端页面最多;
- 所以其实整个关注中最重要的就是service先上层提供的增删改查服务;然后就是controller修改viewObject; 其他的其实只是代码量的问题罢了
代码
@Service
public class FollowService {
@Autowired
JedisAdapter jedisAdapter;
/**
* 用户关注了某个实体,可以关注问题,关注用户,关注评论等任何实体
* @param userId
* @param entityType
* @param entityId
* @return
*/
public boolean follow(int userId, int entityType, int entityId) {
String followerKey = RedisKeyUtil.getFollowerKey(entityType, entityId);
String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType);
Date date = new Date();
Jedis jedis = jedisAdapter.getJedis();
Transaction tx = jedisAdapter.multi(jedis);
tx.zadd(followerKey, date.getTime(), String.valueOf(userId));
tx.zadd(followeeKey, date.getTime(), String.valueOf(entityId));
List<Object> ret = jedisAdapter.exec(tx, jedis);
return ret.size() == 2 && (Long) ret.get(0) > 0 && (Long) ret.get(1) > 0;
}
/**
* 取消关注
* @param userId
* @param entityType
* @param entityId
* @return
*/
public boolean unfollow(int userId, int entityType, int entityId) {
String followerKey = RedisKeyUtil.getFollowerKey(entityType, entityId);
String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType);
Date date = new Date();
Jedis jedis = jedisAdapter.getJedis();
Transaction tx = jedisAdapter.multi(jedis);
tx.zrem(followerKey, String.valueOf(userId));
tx.zrem(followeeKey, String.valueOf(entityId));
List<Object> ret = jedisAdapter.exec(tx, jedis);
return ret.size() == 2 && (Long) ret.get(0) > 0 && (Long) ret.get(1) > 0;
}
public List<Integer> getFollowers(int entityType, int entityId, int count) {
String followerKey = RedisKeyUtil.getFollowerKey(entityType, entityId);
return getIdsFromSet(jedisAdapter.zrevrange(followerKey, 0, count));
}
public List<Integer> getFollowers(int entityType, int entityId, int offset, int count) {
String followerKey = RedisKeyUtil.getFollowerKey(entityType, entityId);
return getIdsFromSet(jedisAdapter.zrevrange(followerKey, offset, offset+count));
}
public List<Integer> getFollowees(int userId, int entityType, int count) {
String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType);
return getIdsFromSet(jedisAdapter.zrevrange(followeeKey, 0, count));
}
public List<Integer> getFollowees(int userId, int entityType, int offset, int count) {
String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType);
return getIdsFromSet(jedisAdapter.zrevrange(followeeKey, offset, offset+count));
}
public long getFollowerCount(int entityType, int entityId) {
String followerKey = RedisKeyUtil.getFollowerKey(entityType, entityId);
return jedisAdapter.zcard(followerKey);
}
public long getFolloweeCount(int userId, int entityType) {
String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType);
return jedisAdapter.zcard(followeeKey);
}
private List<Integer> getIdsFromSet(Set<String> idset) {
List<Integer> ids = new ArrayList<>();
for (String str : idset) {
ids.add(Integer.parseInt(str));
}
return ids;
}
/**
* 判断用户是否关注了某个实体
* @param userId
* @param entityType
* @param entityId
* @return
*/
public boolean isFollower(int userId, int entityType, int entityId) {
String followerKey = RedisKeyUtil.getFollowerKey(entityType, entityId);
return jedisAdapter.zscore(followerKey, String.valueOf(userId)) != null;
}
}