|
@@ -0,0 +1,331 @@
|
|
|
+package com.chelvc.cloud.vehicle.server.service.impl;
|
|
|
+
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
|
+import com.chelvc.cloud.uc.api.dto.UserDTO;
|
|
|
+import com.chelvc.cloud.uc.api.service.UserService;
|
|
|
+import com.chelvc.cloud.vehicle.api.constant.AttentionType;
|
|
|
+import com.chelvc.cloud.vehicle.api.dto.AttentionTotalDTO;
|
|
|
+import com.chelvc.cloud.vehicle.api.dto.AttentionUserDTO;
|
|
|
+import com.chelvc.cloud.vehicle.api.param.QueryAttentionParam;
|
|
|
+import com.chelvc.cloud.vehicle.api.service.AttentionService;
|
|
|
+import com.chelvc.cloud.vehicle.server.dao.AttentionMapper;
|
|
|
+import com.chelvc.cloud.vehicle.server.entity.Attention;
|
|
|
+import com.chelvc.framework.base.exception.ResourceUnavailableException;
|
|
|
+import com.chelvc.framework.common.model.PagedDTO;
|
|
|
+import com.chelvc.framework.common.model.Pagination;
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
+import org.apache.dubbo.config.annotation.DubboReference;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.data.redis.core.RedisTemplate;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.time.ZoneId;
|
|
|
+import java.util.*;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+/**
|
|
|
+ * @author: igl
|
|
|
+ * @date: 2023/8/14 10:11
|
|
|
+ */
|
|
|
+@Service
|
|
|
+@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
|
|
+public class AttentionServiceImpl implements AttentionService {
|
|
|
+
|
|
|
+ private final static String ATTENTION_CACHE_KEY = "vehicle:user:attention:${userId}";
|
|
|
+ private final static String FANS_CACHE_KEY = "vehicle:user:fans:${userId}";
|
|
|
+ private final static String FRIEND_CACHE_KEY = "vehicle:user:friend:${userId}";
|
|
|
+ private final static String TEMP_FRIEND_CACHE_KEY = "vehicle:user:friend:${userId}";
|
|
|
+
|
|
|
+ private final RedisTemplate<String, Object> redisTemplate;
|
|
|
+ private final AttentionMapper attentionMapper;
|
|
|
+
|
|
|
+ @DubboReference
|
|
|
+ private final UserService userService;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void concern(Long userId, Long targetUserId) {
|
|
|
+ if (userId == null || userId.equals(targetUserId)) {
|
|
|
+ throw new ResourceUnavailableException("不能自己关注自己");
|
|
|
+ }
|
|
|
+ LambdaQueryWrapper<Attention> wrapper = Wrappers.lambdaQuery();
|
|
|
+ wrapper.eq(Attention::getUserId, userId);
|
|
|
+ wrapper.eq(Attention::getTarget, targetUserId);
|
|
|
+ Attention attention = attentionMapper.selectOne(wrapper);
|
|
|
+ if(attention != null){
|
|
|
+ int i = attentionMapper.deleteById(attention.getId());
|
|
|
+ if(i != 1){
|
|
|
+ throw new ResourceUnavailableException("取消关注失败");
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ attention = new Attention();
|
|
|
+ attention.setUserId(userId);
|
|
|
+ attention.setTarget(targetUserId);
|
|
|
+ attention.setCreateTime(LocalDateTime.now());
|
|
|
+ int insert = attentionMapper.insert(attention);
|
|
|
+ if(insert != 1){
|
|
|
+ throw new ResourceUnavailableException("关注失败");
|
|
|
+ }
|
|
|
+ /*boolean attention = attention(userId, targetUserId);
|
|
|
+ fans(targetUserId, userId, attention);
|
|
|
+ boolean b = checkAttention(targetUserId, userId);
|
|
|
+ if(attention && b){
|
|
|
+ redisTemplate.opsForZSet()
|
|
|
+ .add(getFriendCacheKey(userId), targetUserId, System.currentTimeMillis());
|
|
|
+ redisTemplate.opsForZSet()
|
|
|
+ .add(getFriendCacheKey(targetUserId), userId, System.currentTimeMillis());
|
|
|
+ } else if (!attention && b) {
|
|
|
+ redisTemplate.opsForZSet().remove(getFriendCacheKey(userId), targetUserId);
|
|
|
+ redisTemplate.opsForZSet().remove(getFriendCacheKey(targetUserId), userId);
|
|
|
+ }*/
|
|
|
+ }
|
|
|
+
|
|
|
+ public boolean checkAttention(Long userId, Long targetUserId){
|
|
|
+ String attentionCacheKey = getAttentionCacheKey(userId);
|
|
|
+ Long rank = redisTemplate.opsForZSet().rank(attentionCacheKey, targetUserId);
|
|
|
+ return rank != null;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Pagination<AttentionUserDTO> page(PagedDTO page, QueryAttentionParam param, Long userId) {
|
|
|
+ if (userId == null) {
|
|
|
+ throw new ResourceUnavailableException("用户不存在");
|
|
|
+ }
|
|
|
+ Long pageCode = page.getPageCode();
|
|
|
+ Long pageSize = page.getPageSize();
|
|
|
+ long start = (pageCode - 1) * pageSize;
|
|
|
+ long end = pageCode * pageSize - 1;
|
|
|
+ AttentionType type = param.getType();
|
|
|
+ Long total = 0L;
|
|
|
+ List<AttentionUserDTO> list = new ArrayList<>();
|
|
|
+ String attentionCacheKey = getAttentionCacheKey(userId);
|
|
|
+ String fansCacheKey = getFansCacheKey(userId);
|
|
|
+ String friendCacheKey = getFriendCacheKey(userId);
|
|
|
+ switch (type) {
|
|
|
+ case ATTENTION:
|
|
|
+ if (Boolean.FALSE.equals(redisTemplate.hasKey(attentionCacheKey))) {
|
|
|
+ setAttentionCache(attentionCacheKey, userId);
|
|
|
+ if (Boolean.FALSE.equals(redisTemplate.hasKey(attentionCacheKey))) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ total = queryCache(attentionCacheKey, list, start, end, AttentionType.ATTENTION, fansCacheKey);
|
|
|
+ break;
|
|
|
+ case FANS:
|
|
|
+ if (Boolean.FALSE.equals(redisTemplate.hasKey(fansCacheKey))) {
|
|
|
+ setFansCache(fansCacheKey, userId);
|
|
|
+ if (Boolean.FALSE.equals(redisTemplate.hasKey(fansCacheKey))) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ total = queryCache(fansCacheKey, list, start, end, AttentionType.FANS, attentionCacheKey);
|
|
|
+ break;
|
|
|
+ case FRIEND:
|
|
|
+ if (Boolean.FALSE.equals(redisTemplate.hasKey(friendCacheKey))) {
|
|
|
+ setFriendCache(friendCacheKey, userId);
|
|
|
+ if (Boolean.FALSE.equals(redisTemplate.hasKey(friendCacheKey))) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ total = queryCache(friendCacheKey, list, start, end, AttentionType.FRIEND, "");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ long quotient = total / pageSize;
|
|
|
+ long remainder = total % pageSize;
|
|
|
+ if(remainder > 0){
|
|
|
+ quotient += quotient;
|
|
|
+ }
|
|
|
+ return Pagination.<AttentionUserDTO>builder().total(total).pages(quotient)
|
|
|
+ .records(list).build();
|
|
|
+ }
|
|
|
+ public void setFriendCache(String cacheKey, Long userId){
|
|
|
+ String tempFriendCacheKey = getTempFriendCacheKey(userId);
|
|
|
+ redisTemplate.opsForZSet().intersectAndStore(getAttentionCacheKey(userId),
|
|
|
+ getFansCacheKey(userId), tempFriendCacheKey);
|
|
|
+ Set<Object> set = redisTemplate.opsForZSet().range(tempFriendCacheKey, 0, -1);
|
|
|
+ if (set != null && set.size() > 0) {
|
|
|
+ set.forEach(e ->{
|
|
|
+ redisTemplate.opsForZSet()
|
|
|
+ .add(cacheKey, e, System.currentTimeMillis());
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ @Override
|
|
|
+ public Map<Long, Boolean> queryAttentionByUserIds(Long userId, List<Long> userIds) {
|
|
|
+ if(userIds == null || userIds.size() == 0){
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ String attentionCacheKey = getAttentionCacheKey(userId);
|
|
|
+ if(Boolean.FALSE.equals(redisTemplate.hasKey(attentionCacheKey))){
|
|
|
+ setAttentionCache(attentionCacheKey, userId);
|
|
|
+ if(Boolean.FALSE.equals(redisTemplate.hasKey(attentionCacheKey))){
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ Map<Long, Boolean> map = new HashMap<>();
|
|
|
+ userIds.forEach(e -> {
|
|
|
+ Long rank = redisTemplate.opsForZSet().rank(attentionCacheKey, e);
|
|
|
+ if(rank == null){
|
|
|
+ map.put(e, false);
|
|
|
+ } else {
|
|
|
+ map.put(e, true);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return map;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public AttentionTotalDTO queryTotalByUserId(Long userId) {
|
|
|
+ if(userId == null){
|
|
|
+ throw new ResourceUnavailableException("用户不存在");
|
|
|
+ }
|
|
|
+ AttentionTotalDTO totalDTO = new AttentionTotalDTO();
|
|
|
+ String attentionCacheKey = getAttentionCacheKey(userId);
|
|
|
+ if(Boolean.FALSE.equals(redisTemplate.hasKey(attentionCacheKey))){
|
|
|
+ setAttentionCache(attentionCacheKey, userId);
|
|
|
+ }
|
|
|
+ totalDTO.setAttentionTotal(redisTemplate.opsForZSet().zCard(attentionCacheKey));
|
|
|
+ String fansCacheKey = getFansCacheKey(userId);
|
|
|
+ if(Boolean.FALSE.equals(redisTemplate.hasKey(fansCacheKey))){
|
|
|
+ setFansCache(fansCacheKey, userId);
|
|
|
+ }
|
|
|
+ totalDTO.setFansTotal(redisTemplate.opsForZSet().zCard(fansCacheKey));
|
|
|
+ String friendCacheKey = getFriendCacheKey(userId);
|
|
|
+ if(Boolean.FALSE.equals(redisTemplate.hasKey(friendCacheKey))){
|
|
|
+ setFriendCache(friendCacheKey, userId);
|
|
|
+ }
|
|
|
+ totalDTO.setFriendTotal(redisTemplate.opsForZSet().zCard(friendCacheKey));
|
|
|
+ return totalDTO;
|
|
|
+ }
|
|
|
+
|
|
|
+ public Long queryCache(String cacheKey, List<AttentionUserDTO> list, Long start,
|
|
|
+ Long end, AttentionType type, String key) {
|
|
|
+ Long total = redisTemplate.opsForZSet().zCard(cacheKey);
|
|
|
+ Set<Object> set = redisTemplate.opsForZSet()
|
|
|
+ .reverseRange(cacheKey, start, end);
|
|
|
+ if (set != null && set.size() > 0) {
|
|
|
+ List<Long> userIds = set.stream().map(e -> (Long) e).collect(Collectors.toList());
|
|
|
+ Map<Long, UserDTO> map = userService.queryUserByIds(userIds);
|
|
|
+ set.forEach(e -> {
|
|
|
+ AttentionUserDTO attentionUserDTO = new AttentionUserDTO();
|
|
|
+ attentionUserDTO.setUserDTO(map.get((Long)e));
|
|
|
+ switch (type){
|
|
|
+ case ATTENTION:
|
|
|
+ Long attention = redisTemplate.opsForZSet().rank(key, e);
|
|
|
+ if(attention == null){
|
|
|
+ //对方未关注
|
|
|
+ attentionUserDTO.setFlag(0);
|
|
|
+ } else {
|
|
|
+ attentionUserDTO.setFlag(2);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case FANS:
|
|
|
+ Long fans = redisTemplate.opsForZSet().rank(key, e);
|
|
|
+ if(fans == null){
|
|
|
+ //自己未关注
|
|
|
+ attentionUserDTO.setFlag(1);
|
|
|
+ } else {
|
|
|
+ attentionUserDTO.setFlag(2);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case FRIEND:
|
|
|
+ attentionUserDTO.setFlag(2);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ list.add(attentionUserDTO);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ return total;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void fans(Long userId, Long fansUserId, boolean b) {
|
|
|
+ String cacheKey = getFansCacheKey(userId);
|
|
|
+ if (Boolean.TRUE.equals(redisTemplate.hasKey(cacheKey))) {
|
|
|
+ if (b) {
|
|
|
+ redisTemplate.opsForZSet()
|
|
|
+ .add(cacheKey, fansUserId, System.currentTimeMillis());
|
|
|
+ } else {
|
|
|
+ redisTemplate.opsForZSet().remove(cacheKey, fansUserId);
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ setFansCache(cacheKey, userId);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setFansCache(String cacheKey, Long userId){
|
|
|
+ LambdaQueryWrapper<Attention> lwq = Wrappers.lambdaQuery();
|
|
|
+ lwq.eq(Attention::getTarget, userId);
|
|
|
+ lwq.orderByDesc(Attention::getCreateTime);
|
|
|
+ List<Attention> list = attentionMapper.selectList(lwq);
|
|
|
+ if (list != null && list.size() > 0) {
|
|
|
+ list.forEach(e -> {
|
|
|
+ LocalDateTime createTime = e.getCreateTime();
|
|
|
+ long milliseconds = createTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
|
|
|
+ redisTemplate.opsForZSet().add(cacheKey, e.getUserId(), milliseconds);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ redisTemplate.expire(cacheKey, 60 * 60 * 24 * 7, TimeUnit.SECONDS);
|
|
|
+ }
|
|
|
+
|
|
|
+ public boolean attention(Long userId, Long targetUserId) {
|
|
|
+ String cacheKey = getAttentionCacheKey(userId);
|
|
|
+ if (Boolean.TRUE.equals(redisTemplate.hasKey(cacheKey))) {
|
|
|
+ return attentionOperate(cacheKey, userId, targetUserId);
|
|
|
+ }
|
|
|
+ setAttentionCache(cacheKey, userId);
|
|
|
+ return attentionOperate(cacheKey, userId, targetUserId);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setAttentionCache(String cacheKey, Long userId){
|
|
|
+ LambdaQueryWrapper<Attention> lwq = Wrappers.lambdaQuery();
|
|
|
+ lwq.eq(Attention::getUserId, userId);
|
|
|
+ lwq.orderByDesc(Attention::getCreateTime);
|
|
|
+ List<Attention> list = attentionMapper.selectList(lwq);
|
|
|
+ if (list != null && list.size() > 0) {
|
|
|
+ list.forEach(e -> {
|
|
|
+ LocalDateTime createTime = e.getCreateTime();
|
|
|
+ long milliseconds = createTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
|
|
|
+ redisTemplate.opsForZSet().add(cacheKey, e.getTarget(), milliseconds);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ redisTemplate.expire(cacheKey, 60 * 60 * 24 * 7, TimeUnit.SECONDS);
|
|
|
+ }
|
|
|
+
|
|
|
+ public boolean attentionOperate(String cacheKey, Long userId, Long targetUserId) {
|
|
|
+ Boolean b = redisTemplate.opsForZSet()
|
|
|
+ .add(cacheKey, targetUserId, System.currentTimeMillis());
|
|
|
+ if (Boolean.FALSE.equals(b)) {
|
|
|
+ LambdaQueryWrapper<Attention> lwq = Wrappers.lambdaQuery();
|
|
|
+ lwq.eq(Attention::getUserId, userId);
|
|
|
+ lwq.eq(Attention::getTarget, targetUserId);
|
|
|
+ attentionMapper.delete(lwq);
|
|
|
+ redisTemplate.opsForZSet().remove(cacheKey, targetUserId);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ Attention entity = new Attention();
|
|
|
+ entity.setUserId(userId);
|
|
|
+ entity.setTarget(targetUserId);
|
|
|
+ entity.setCreateTime(LocalDateTime.now());
|
|
|
+ attentionMapper.insert(entity);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ private String getAttentionCacheKey(Long userId) {
|
|
|
+ return ATTENTION_CACHE_KEY.replace("${userId}", String.valueOf(userId));
|
|
|
+ }
|
|
|
+
|
|
|
+ private String getTempFriendCacheKey(Long userId) {
|
|
|
+ return TEMP_FRIEND_CACHE_KEY.replace("${userId}", String.valueOf(userId));
|
|
|
+ }
|
|
|
+
|
|
|
+ private String getFansCacheKey(Long userId) {
|
|
|
+ return FANS_CACHE_KEY.replace("${userId}", String.valueOf(userId));
|
|
|
+ }
|
|
|
+
|
|
|
+ private String getFriendCacheKey(Long userId) {
|
|
|
+ return FRIEND_CACHE_KEY.replace("${userId}", String.valueOf(userId));
|
|
|
+ }
|
|
|
+}
|