|
|
@@ -0,0 +1,119 @@
|
|
|
+package cn.seecoder.fdroidrepository.Service.ServiceImpl;
|
|
|
+
|
|
|
+
|
|
|
+import cn.seecoder.fdroidrepository.DataObject.User;
|
|
|
+import cn.seecoder.fdroidrepository.utils.RedisUtil;
|
|
|
+import cn.seecoder.fdroidrepository.utils.Tools;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.data.redis.core.RedisTemplate;
|
|
|
+import org.springframework.data.redis.core.script.DefaultRedisScript;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import java.util.*;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
+
|
|
|
+@Service
|
|
|
+public class FollowService {
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private RedisTemplate redisTemplate;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private UserServiceImpl userService;
|
|
|
+
|
|
|
+ public void follow(int followerId, int followeeId) throws InterruptedException {
|
|
|
+ String followeeKey = RedisUtil.getFolloweeKey(String.valueOf(followerId));
|
|
|
+ String followerKey = RedisUtil.getFollowerKey(String.valueOf(followeeId));
|
|
|
+ String followLock = RedisUtil.getLockByName(followeeKey);
|
|
|
+ String uuid = Tools.generateUUID();
|
|
|
+ Boolean store = redisTemplate.opsForValue().setIfAbsent(followLock, uuid, 3, TimeUnit.SECONDS);
|
|
|
+ if (Boolean.TRUE.equals(store)) {
|
|
|
+ redisTemplate.opsForZSet().add(followerKey,followerId,System.currentTimeMillis());
|
|
|
+ redisTemplate.opsForZSet().add(followeeKey, followeeId, System.currentTimeMillis());
|
|
|
+ String uuidLock = (String) redisTemplate.opsForValue().get(followLock);
|
|
|
+ if (uuid.equals(uuidLock)) {
|
|
|
+ String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
|
|
|
+ DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
|
|
|
+ redisScript.setScriptText(script);
|
|
|
+ redisScript.setResultType(Long.class);
|
|
|
+ Long execute = (Long) redisTemplate.execute(redisScript, Arrays.asList(followLock), uuidLock);
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ Thread.sleep(100);
|
|
|
+ follow(followerId,followeeId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void unFollow(int followerId,int followeeId) throws InterruptedException {
|
|
|
+ String followeeKey = RedisUtil.getFolloweeKey(String.valueOf(followerId));
|
|
|
+ String followerKey = RedisUtil.getFollowerKey(String.valueOf(followeeId));
|
|
|
+ String followLock =RedisUtil.getLockByName(followeeKey);
|
|
|
+ String uuid = Tools.generateUUID();
|
|
|
+ Boolean store = redisTemplate.opsForValue().setIfAbsent(followLock,uuid,3,TimeUnit.SECONDS);
|
|
|
+ if(store) {
|
|
|
+ redisTemplate.opsForZSet().remove(followeeKey,followeeId);
|
|
|
+ redisTemplate.opsForZSet().remove(followerKey,followerId);
|
|
|
+ String uuidLock = (String) redisTemplate.opsForValue().get(followLock);
|
|
|
+ if(uuid.equals(uuidLock)){
|
|
|
+ String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
|
|
|
+ DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
|
|
|
+ redisScript.setScriptText(script);
|
|
|
+ redisScript.setResultType(Long.class);
|
|
|
+ Long execute = (Long) redisTemplate.execute(redisScript, Arrays.asList(followLock), uuidLock);
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ Thread.sleep(100);
|
|
|
+ unFollow(followerId,followeeId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public long getFolloweeCount(int userId){
|
|
|
+ String followKey =RedisUtil.getFolloweeKey(String.valueOf(userId));
|
|
|
+ return redisTemplate.opsForZSet().zCard(followKey);
|
|
|
+ }
|
|
|
+
|
|
|
+ public long getFollowerCount(int userId){
|
|
|
+ String followKey = RedisUtil.getFollowerKey(String.valueOf(userId));
|
|
|
+ return redisTemplate.opsForZSet().zCard(followKey);
|
|
|
+ }
|
|
|
+
|
|
|
+ public List<Map<String, Object>> findFollowees(int userId){
|
|
|
+ String followeeKey = RedisUtil.getFolloweeKey(String.valueOf(userId));
|
|
|
+ Set<Integer> targetIds = redisTemplate.opsForZSet().reverseRange(followeeKey,0,-1);
|
|
|
+ if(targetIds==null||targetIds.isEmpty()){
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ List<Map<String,Object>> list=new ArrayList<>();
|
|
|
+ for(Integer targetId: targetIds){
|
|
|
+ Map<String,Object> map = new HashMap<>();
|
|
|
+ User user=userService.loadUserByUserId(targetId);
|
|
|
+ map.put("username",user.getUsername());
|
|
|
+ Double score =redisTemplate.opsForZSet().score(followeeKey,targetId);
|
|
|
+ map.put("followTime",new Date(score.longValue()));
|
|
|
+ list.add(map);
|
|
|
+ }
|
|
|
+ return list;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public List<Map<String, Object>> findFollowers(int userId){
|
|
|
+ String followerKey = RedisUtil.getFollowerKey(String.valueOf(userId));
|
|
|
+ Set<Integer> targetIds = redisTemplate.opsForZSet().reverseRange(followerKey,0,-1);
|
|
|
+ if(targetIds==null||targetIds.isEmpty()){
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ List<Map<String,Object>> list=new ArrayList<>();
|
|
|
+ for(Integer targetId: targetIds){
|
|
|
+ Map<String,Object> map = new HashMap<>();
|
|
|
+ User user=userService.loadUserByUserId(targetId);
|
|
|
+ map.put("username",user.getUsername());
|
|
|
+ Double score =redisTemplate.opsForZSet().score(followerKey,targetId);
|
|
|
+ map.put("followTime",new Date(score.longValue()));
|
|
|
+ list.add(map);
|
|
|
+ }
|
|
|
+ return list;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+}
|