followedWrapper = new LambdaQueryWrapper<>();
86 | followedWrapper.eq(UserDO::getFollowerCount, followerCount);
87 | followed.setFollowerCount(followerCount + 1);
88 | /**@author zzzi
89 | * @date 2024/4/14 17:21
90 | * 粉丝关注量超过1W就将用户添加到大V列表中,认为是大V
91 | */
92 | if (followerCount + 1 >= 10000) {
93 | redisTemplate.opsForSet().add(RedisKeys.USER_HOT, followed.getUserId().toString());
94 | }
95 | int updateFollowed = userMapper.update(followed, followedWrapper);
96 | if (updateFollowed != 1) {
97 | throw new FollowException("用户关注失败");
98 | }
99 |
100 | //调用方法更新用户缓存
101 | String followerJson = gson.toJson(follower);
102 | String followedJson = gson.toJson(followed);
103 |
104 | updateUserInfoUtils.updateUserInfoCache(followerId, followerJson);
105 | updateUserInfoUtils.updateUserInfoCache(followedId, followedJson);
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/user-service/src/main/java/com/zzzi/userservice/listener/PostVideoListener.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.userservice.listener;
2 |
3 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
4 | import com.google.gson.Gson;
5 | import com.zzzi.common.constant.RabbitMQKeys;
6 | import com.zzzi.userservice.entity.UserDO;
7 | import com.zzzi.userservice.mapper.UserMapper;
8 | import com.zzzi.common.utils.UpdateUserInfoUtils;
9 | import lombok.extern.slf4j.Slf4j;
10 | import org.springframework.amqp.core.ExchangeTypes;
11 | import org.springframework.amqp.rabbit.annotation.Exchange;
12 | import org.springframework.amqp.rabbit.annotation.Queue;
13 | import org.springframework.amqp.rabbit.annotation.QueueBinding;
14 | import org.springframework.amqp.rabbit.annotation.RabbitListener;
15 | import org.springframework.aop.framework.AopContext;
16 | import org.springframework.beans.factory.annotation.Autowired;
17 | import org.springframework.messaging.handler.annotation.Payload;
18 | import org.springframework.stereotype.Service;
19 | import org.springframework.transaction.annotation.Transactional;
20 |
21 |
22 | /**
23 | * @author zzzi
24 | * @date 2024/3/27 15:44
25 | * 在这里监听投稿的操作,便于更新用户表中的作品数
26 | * 并且更新缓存
27 | */
28 | @Service
29 | @Slf4j
30 | public class PostVideoListener {
31 |
32 | @Autowired
33 | private UserMapper userMapper;
34 | @Autowired
35 | private UpdateUserInfoUtils updateUserInfoUtils;
36 | @Autowired
37 | private Gson gson;
38 |
39 |
40 | /**
41 | * @author zzzi
42 | * @date 2024/3/27 16:26
43 | * 在这里需要修改用户表中的作品数
44 | * 以及修改用户缓存中的数据
45 | *
46 | * 这里需要互斥锁,因为修改缓存需要互斥
47 | */
48 | @RabbitListener(
49 | bindings = @QueueBinding(
50 | value = @Queue(name = "direct.post_video"),
51 | exchange = @Exchange(name = RabbitMQKeys.POST_VIDEO_EXCHANGE, type = ExchangeTypes.DIRECT),
52 | key = {RabbitMQKeys.VIDEO_POST}
53 | )
54 | )
55 | @Transactional
56 | public void listenToPostVideo(@Payload Long authorId) {
57 | log.info("监听到用户投稿操作的用户id为:{}", authorId);
58 | //查询得到用户原有信息
59 | UserDO userDO = userMapper.selectById(authorId);
60 | Integer workCount = userDO.getWorkCount();
61 |
62 | //更新用户作品信息
63 | userDO.setWorkCount(workCount + 1);
64 | LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
65 | //加上乐观锁
66 | queryWrapper.eq(UserDO::getWorkCount, workCount);
67 | //更新用户表中的作品数
68 | int update = userMapper.update(userDO, queryWrapper);
69 | if (update != 1) {
70 | //手动实现CAS算法
71 | PostVideoListener postVideoListener = (PostVideoListener) AopContext.currentProxy();
72 | postVideoListener.listenToPostVideo(authorId);
73 | }
74 |
75 |
76 | String userDOJson = gson.toJson(userDO);
77 | //更新用户的缓存
78 | updateUserInfoUtils.updateUserInfoCache(authorId, userDOJson);
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/user-service/src/main/java/com/zzzi/userservice/listener/UnFavoriteListenerOne.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.userservice.listener;
2 |
3 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
4 | import com.google.gson.Gson;
5 | import com.zzzi.common.constant.RabbitMQKeys;
6 | import com.zzzi.userservice.entity.UserDO;
7 | import com.zzzi.userservice.mapper.UserMapper;
8 | import com.zzzi.common.utils.UpdateUserInfoUtils;
9 | import lombok.extern.slf4j.Slf4j;
10 | import org.springframework.amqp.rabbit.annotation.RabbitListener;
11 | import org.springframework.aop.framework.AopContext;
12 | import org.springframework.beans.factory.annotation.Autowired;
13 | import org.springframework.messaging.handler.annotation.Payload;
14 | import org.springframework.stereotype.Service;
15 | import org.springframework.transaction.annotation.Transactional;
16 |
17 |
18 | /**
19 | * @author zzzi
20 | * @date 2024/3/29 16:38
21 | * 在这里异步的更新用户的基本信息
22 | */
23 | @Service
24 | @Slf4j
25 | public class UnFavoriteListenerOne {
26 | @Autowired
27 | private UserMapper userMapper;
28 | @Autowired
29 | private UpdateUserInfoUtils updateUserInfoUtils;
30 | @Autowired
31 | private Gson gson;
32 |
33 |
34 | /**
35 | * @author zzzi
36 | * @date 2024/3/29 16:49
37 | * 用户关注在这里更新双方的用户信息
38 | */
39 | @RabbitListener(queues = {RabbitMQKeys.UN_FAVORITE_USER})
40 | @Transactional
41 | public void listenToUnFavorite(@Payload long[] ids) {
42 | log.info("第一个消费者监听到用户取消点赞操作,更新用户信息");
43 | //两个用户都更新
44 | UserDO userA = userMapper.selectById(ids[0]);
45 |
46 | //A的点赞数+1
47 | Integer favoriteCount = userA.getFavoriteCount();
48 | LambdaQueryWrapper queryWrapperA = new LambdaQueryWrapper<>();
49 | //加上乐观锁,判断当前更新时查到的数据是否被其他线程更新过了
50 | queryWrapperA.eq(UserDO::getFavoriteCount, favoriteCount);
51 | userA.setFavoriteCount(favoriteCount - 1);
52 | int updateA = userMapper.update(userA, queryWrapperA);
53 | if (updateA != 1) {
54 | //手动实现CAS算法
55 | UnFavoriteListenerOne UnFavoriteListener = (UnFavoriteListenerOne) AopContext.currentProxy();
56 | UnFavoriteListener.listenToUnFavorite(ids);
57 | }
58 |
59 |
60 | //B的获赞总数+1
61 | UserDO userB = userMapper.selectById(ids[1]);
62 | Long totalFavorited = userB.getTotalFavorited();
63 | LambdaQueryWrapper queryWrapperB = new LambdaQueryWrapper<>();
64 | //加上乐观锁,判断当前更新时查到的数据是否被其他线程更新过了
65 | queryWrapperB.eq(UserDO::getTotalFavorited, totalFavorited);
66 | userB.setTotalFavorited(totalFavorited - 1);
67 | /**@author zzzi
68 | * @date 2024/4/14 17:20
69 | * 获赞总数小于1W时从大V列表中删除
70 | */
71 | if (totalFavorited - 1 < 10000) {
72 | updateUserInfoUtils.deleteHotUserFormCache(userB.getUserId());
73 | }
74 | int updateB = userMapper.update(userB, queryWrapperB);
75 | if (updateB != 1) {
76 | //手动实现CAS算法
77 | UnFavoriteListenerOne UnFavoriteListener = (UnFavoriteListenerOne) AopContext.currentProxy();
78 | UnFavoriteListener.listenToUnFavorite(ids);
79 | }
80 |
81 | //更新两个用户的缓存信息
82 | String userAJson = gson.toJson(userA);
83 | String userBJson = gson.toJson(userB);
84 |
85 | updateUserInfoUtils.updateUserInfoCache(userA.getUserId(), userAJson);
86 | updateUserInfoUtils.updateUserInfoCache(userB.getUserId(), userBJson);
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/user-service/src/main/java/com/zzzi/userservice/listener/UnFavoriteListenerTwo.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.userservice.listener;
2 |
3 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
4 | import com.google.gson.Gson;
5 | import com.zzzi.common.constant.RabbitMQKeys;
6 | import com.zzzi.userservice.entity.UserDO;
7 | import com.zzzi.userservice.mapper.UserMapper;
8 | import com.zzzi.common.utils.UpdateUserInfoUtils;
9 | import lombok.extern.slf4j.Slf4j;
10 | import org.springframework.amqp.rabbit.annotation.RabbitListener;
11 | import org.springframework.aop.framework.AopContext;
12 | import org.springframework.beans.factory.annotation.Autowired;
13 | import org.springframework.messaging.handler.annotation.Payload;
14 | import org.springframework.stereotype.Service;
15 | import org.springframework.transaction.annotation.Transactional;
16 |
17 |
18 | /**
19 | * @author zzzi
20 | * @date 2024/3/29 16:38
21 | * 在这里异步的更新用户的基本信息
22 | */
23 | @Service
24 | @Slf4j
25 | public class UnFavoriteListenerTwo {
26 | @Autowired
27 | private UserMapper userMapper;
28 | @Autowired
29 | private UpdateUserInfoUtils updateUserInfoUtils;
30 | @Autowired
31 | private Gson gson;
32 |
33 |
34 | /**
35 | * @author zzzi
36 | * @date 2024/3/29 16:49
37 | * 用户关注在这里更新双方的用户信息
38 | */
39 | @RabbitListener(queues = {RabbitMQKeys.UN_FAVORITE_USER})
40 | @Transactional
41 | public void listenToUnFavorite(@Payload long[] ids) {
42 | log.info("第二个消费者监听到用户取消点赞操作,更新用户信息");
43 | //两个用户都更新
44 | UserDO userA = userMapper.selectById(ids[0]);
45 |
46 | //A的点赞数+1
47 | Integer favoriteCount = userA.getFavoriteCount();
48 | LambdaQueryWrapper queryWrapperA = new LambdaQueryWrapper<>();
49 | //加上乐观锁,判断当前更新时查到的数据是否被其他线程更新过了
50 | queryWrapperA.eq(UserDO::getFavoriteCount, favoriteCount);
51 | //todo:两步自旋异常更新数据库
52 | userA.setFavoriteCount(favoriteCount - 1);
53 | int updateA = userMapper.update(userA, queryWrapperA);
54 | if (updateA != 1) {
55 | //手动实现CAS算法
56 | UnFavoriteListenerOne UnFavoriteListener = (UnFavoriteListenerOne) AopContext.currentProxy();
57 | UnFavoriteListener.listenToUnFavorite(ids);
58 | }
59 |
60 |
61 | //B的获赞总数+1
62 | UserDO userB = userMapper.selectById(ids[1]);
63 | Long totalFavorited = userB.getTotalFavorited();
64 | LambdaQueryWrapper queryWrapperB = new LambdaQueryWrapper<>();
65 | //加上乐观锁,判断当前更新时查到的数据是否被其他线程更新过了
66 | queryWrapperB.eq(UserDO::getTotalFavorited, totalFavorited);
67 | userB.setTotalFavorited(totalFavorited - 1);
68 | /**@author zzzi
69 | * @date 2024/4/14 17:20
70 | * 获赞总数小于1W时从大V列表中删除
71 | */
72 | if (totalFavorited - 1 < 10000) {
73 | updateUserInfoUtils.deleteHotUserFormCache(userB.getUserId());
74 | }
75 | int updateB = userMapper.update(userB, queryWrapperB);
76 | if (updateB != 1) {
77 | //手动实现CAS算法
78 | UnFavoriteListenerOne UnFavoriteListener = (UnFavoriteListenerOne) AopContext.currentProxy();
79 | UnFavoriteListener.listenToUnFavorite(ids);
80 | }
81 |
82 | //更新两个用户的缓存信息
83 | String userAJson = gson.toJson(userA);
84 | String userBJson = gson.toJson(userB);
85 |
86 | updateUserInfoUtils.updateUserInfoCache(userA.getUserId(), userAJson);
87 | updateUserInfoUtils.updateUserInfoCache(userB.getUserId(), userBJson);
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/user-service/src/main/java/com/zzzi/userservice/listener/UnFollowListener.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.userservice.listener;
2 |
3 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
4 | import com.google.gson.Gson;
5 | import com.zzzi.common.constant.RabbitMQKeys;
6 | import com.zzzi.common.exception.FollowException;
7 | import com.zzzi.userservice.entity.UserDO;
8 | import com.zzzi.userservice.entity.UserFollowDO;
9 | import com.zzzi.userservice.mapper.UserMapper;
10 | import lombok.extern.slf4j.Slf4j;
11 | import org.springframework.amqp.core.ExchangeTypes;
12 | import com.zzzi.common.utils.UpdateUserInfoUtils;
13 | import org.springframework.amqp.rabbit.annotation.Exchange;
14 | import org.springframework.amqp.rabbit.annotation.Queue;
15 | import org.springframework.amqp.rabbit.annotation.QueueBinding;
16 | import org.springframework.amqp.rabbit.annotation.RabbitListener;
17 | import org.springframework.aop.framework.AopContext;
18 | import org.springframework.beans.factory.annotation.Autowired;
19 | import org.springframework.messaging.handler.annotation.Payload;
20 | import org.springframework.stereotype.Service;
21 | import org.springframework.transaction.annotation.Transactional;
22 |
23 | /**
24 | * @author zzzi
25 | * @date 2024/3/29 16:59
26 | * 这里执行取消关注的逻辑
27 | */
28 | @Service
29 | @Slf4j
30 | public class UnFollowListener {
31 |
32 | @Autowired
33 | private UserMapper userMapper;
34 | @Autowired
35 | private UpdateUserInfoUtils updateUserInfoUtils;
36 | @Autowired
37 | private Gson gson;
38 |
39 |
40 | /**
41 | * @author zzzi
42 | * @date 2024/3/29 16:49
43 | * 用户关注在这里更新双方的用户信息
44 | */
45 | @RabbitListener(
46 | bindings = @QueueBinding(
47 | value = @Queue(name = "direct.un_follow"),
48 | exchange = @Exchange(name = RabbitMQKeys.FOLLOW_EXCHANGE, type = ExchangeTypes.DIRECT),
49 | key = {RabbitMQKeys.UN_FOLLOW_KEY}
50 | )
51 | )
52 | @Transactional
53 | public void listenToUnFollow(@Payload String userUnFollowDOJson) {
54 | log.info("监听到用户取消关注");
55 | //将接收到的实体转换成实体类
56 | UserFollowDO userUnFollowDO = gson.fromJson(userUnFollowDOJson, UserFollowDO.class);
57 |
58 | //得到取消关注者和被取消关注者的id
59 | Long unFollowerId = userUnFollowDO.getFollowerId();
60 | Long unFollowedId = userUnFollowDO.getFollowedId();
61 |
62 | //得到取消关注者的信息
63 | UserDO unFollower = userMapper.selectById(unFollowerId);
64 |
65 | //更新取消关注者的关注数
66 | Integer followCount = unFollower.getFollowCount();
67 | LambdaQueryWrapper followWrapper = new LambdaQueryWrapper<>();
68 | //加上乐观锁
69 | followWrapper.eq(UserDO::getFollowCount, followCount);
70 | unFollower.setFollowCount(followCount - 1);
71 | int updateUnFollower = userMapper.update(unFollower, followWrapper);
72 | if (updateUnFollower != 1) {
73 | //手动实现CAS算法
74 | UnFollowListener unFollowListener = (UnFollowListener) AopContext.currentProxy();
75 | unFollowListener.listenToUnFollow(userUnFollowDOJson);
76 | }
77 |
78 | //更新被取消关注者的粉丝数
79 | //得到被取消关注者的信息
80 | UserDO unFollowed = userMapper.selectById(unFollowedId);
81 | Integer followerCount = unFollowed.getFollowerCount();
82 | LambdaQueryWrapper followedWrapper = new LambdaQueryWrapper<>();
83 | //加上乐观锁
84 | followedWrapper.eq(UserDO::getFollowerCount, followerCount);
85 | unFollowed.setFollowerCount(followerCount - 1);
86 | /**@author zzzi
87 | * @date 2024/4/14 17:34
88 | * 当前用户的粉丝数小于1W,此时将当前用户从大V列表中删除
89 | */
90 | if (followerCount - 1 < 10000) {
91 | updateUserInfoUtils.deleteHotUserFormCache(unFollowed.getUserId());
92 | }
93 | int updateUnFollowed = userMapper.update(unFollowed, followedWrapper);
94 | if (updateUnFollowed != 1) {
95 | //手动实现CAS算法
96 | UnFollowListener unFollowListener = (UnFollowListener) AopContext.currentProxy();
97 | unFollowListener.listenToUnFollow(userUnFollowDOJson);
98 | }
99 |
100 | //调用方法更新用户缓存
101 | String followerJson = gson.toJson(unFollower);//主动取消关注者
102 | String followedJson = gson.toJson(unFollowed);//被动取消关注者
103 |
104 | updateUserInfoUtils.updateUserInfoCache(unFollowerId, followerJson);
105 | updateUserInfoUtils.updateUserInfoCache(unFollowedId, followedJson);
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/user-service/src/main/java/com/zzzi/userservice/mapper/MessageMapper.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.userservice.mapper;
2 |
3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
4 | import com.zzzi.userservice.entity.MessageDO;
5 | import org.apache.ibatis.annotations.Mapper;
6 |
7 | @Mapper
8 | public interface MessageMapper extends BaseMapper {
9 | }
10 |
--------------------------------------------------------------------------------
/user-service/src/main/java/com/zzzi/userservice/mapper/RelationMapper.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.userservice.mapper;
2 |
3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
4 | import com.zzzi.userservice.entity.UserFollowDO;
5 | import org.apache.ibatis.annotations.Mapper;
6 |
7 | @Mapper
8 | public interface RelationMapper extends BaseMapper {
9 | }
10 |
--------------------------------------------------------------------------------
/user-service/src/main/java/com/zzzi/userservice/mapper/UserMapper.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.userservice.mapper;
2 |
3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
4 | import com.zzzi.userservice.entity.UserDO;
5 | import org.apache.ibatis.annotations.Mapper;
6 |
7 | @Mapper
8 | public interface UserMapper extends BaseMapper {
9 | }
10 |
--------------------------------------------------------------------------------
/user-service/src/main/java/com/zzzi/userservice/service/MessageService.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.userservice.service;
2 |
3 | import com.baomidou.mybatisplus.extension.service.IService;
4 | import com.zzzi.common.result.MessageVO;
5 | import com.zzzi.userservice.entity.MessageDO;
6 |
7 | import java.util.List;
8 |
9 | public interface MessageService extends IService {
10 | void messageAction(String token, String to_user_id, String content);
11 |
12 | List getMessageList(String token, String to_user_id);
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/user-service/src/main/java/com/zzzi/userservice/service/RelationService.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.userservice.service;
2 |
3 | import com.baomidou.mybatisplus.extension.service.IService;
4 | import com.zzzi.common.result.UserVO;
5 | import com.zzzi.userservice.entity.UserFollowDO;
6 |
7 | import java.util.List;
8 |
9 | public interface RelationService extends IService {
10 | void followAction(String token, Long to_user_id);
11 |
12 | void followUnAction(String token, Long to_user_id1);
13 |
14 | List getFollowList(String user_id, String token);
15 |
16 | List getFollowerList(String user_id, String token);
17 |
18 | List getFriendList(String user_id, String token);
19 | }
20 |
--------------------------------------------------------------------------------
/user-service/src/main/java/com/zzzi/userservice/service/UserService.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.userservice.service;
2 |
3 | import com.baomidou.mybatisplus.extension.service.IService;
4 | import com.zzzi.userservice.dto.UserDTO;
5 | import com.zzzi.userservice.entity.UserDO;
6 | import com.zzzi.common.result.UserVO;
7 |
8 | public interface UserService extends IService {
9 | UserDTO login(String username, String password);
10 |
11 | UserDTO register(String username, String password);
12 |
13 | UserVO getUserInfo(String user_id);
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/user-service/src/main/java/com/zzzi/userservice/service/impl/MessageServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.userservice.service.impl;
2 |
3 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
4 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
5 | import com.zzzi.common.result.MessageVO;
6 | import com.zzzi.common.utils.JwtUtils;
7 | import com.zzzi.common.utils.UpdateTokenUtils;
8 | import com.zzzi.userservice.entity.MessageDO;
9 | import com.zzzi.userservice.mapper.MessageMapper;
10 | import com.zzzi.userservice.service.MessageService;
11 | import lombok.extern.slf4j.Slf4j;
12 | import org.springframework.beans.factory.annotation.Autowired;
13 | import org.springframework.stereotype.Service;
14 | import org.springframework.transaction.annotation.Transactional;
15 |
16 | import java.util.ArrayList;
17 | import java.util.List;
18 |
19 | @Service
20 | @Slf4j
21 | public class MessageServiceImpl extends ServiceImpl implements MessageService {
22 | @Autowired
23 | private MessageMapper messageMapper;
24 | @Autowired
25 | private UpdateTokenUtils updateTokenUtils;
26 |
27 | /**
28 | * @author zzzi
29 | * @date 2024/4/4 14:54
30 | * 直接将当前两个用户的消息保存到数据库中
31 | */
32 | @Override
33 | @Transactional
34 | public void messageAction(String token, String to_user_id, String content) {
35 | log.info("用户发送消息service,用户token为:{},to_user_id为:{}", token, to_user_id);
36 | //解析得到消息发送方id
37 | Long fromUserId = JwtUtils.getUserIdByToken(token);
38 | Long toUserId = Long.valueOf(to_user_id);
39 | MessageDO messageDO = new MessageDO();
40 | messageDO.setFromUserId(fromUserId);
41 | messageDO.setToUserId(toUserId);
42 | messageDO.setContent(content);
43 |
44 | //将其插入到数据库中
45 | int insert = messageMapper.insert(messageDO);
46 | if (insert != 1) {//插入失败
47 | throw new RuntimeException("用户发送消息失败");
48 | }
49 | //更新发送方的token
50 | updateTokenUtils.updateTokenExpireTimeUtils(fromUserId.toString());
51 | }
52 |
53 | @Override
54 | public List getMessageList(String token, String to_user_id) {
55 | log.info("获取用户消息列表,token为:{},to_user_id为:{}", token, to_user_id);
56 | List message_list = new ArrayList<>();
57 | //解析得到用户的id
58 | Long fromUserId = JwtUtils.getUserIdByToken(token);
59 | //从数据库中查询得到所有的消息列表
60 | /**@author zzzi
61 | * @date 2024/4/4 16:25
62 | * 这里获取的是
63 | */
64 | LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
65 | queryWrapper.eq(MessageDO::getFromUserId, fromUserId).eq(MessageDO::getToUserId, to_user_id);
66 |
67 | //将获得的所有MessageDO打包成MessageVO
68 | List messageDOList = messageMapper.selectList(queryWrapper);
69 | for (MessageDO messageDO : messageDOList) {
70 | MessageVO messageVO = packageMessageVO(messageDO);
71 | message_list.add(messageVO);
72 | }
73 | //更新消息获取方的token
74 | updateTokenUtils.updateTokenExpireTimeUtils(fromUserId.toString());
75 | return message_list;
76 | }
77 |
78 | /**
79 | * @author zzzi
80 | * @date 2024/4/4 15:01
81 | * 打包一个MessageVO
82 | */
83 | private MessageVO packageMessageVO(MessageDO messageDO) {
84 | MessageVO messageVO = new MessageVO();
85 | messageVO.setId(messageDO.getMessageId());
86 | messageVO.setContent(messageDO.getContent());
87 | messageVO.setCreate_time(messageDO.getCreateTime().getTime());
88 |
89 | return messageVO;
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/user-service/src/main/resources/application.txt:
--------------------------------------------------------------------------------
1 | spring:
2 | # 数据库相关配置
3 | main:
4 | allow-bean-definition-overriding: true
5 | shardingsphere:
6 | datasource:
7 | ds:
8 | maxPoolSize: 100
9 | # master数据库连接信息
10 | master0:
11 | driver-class-name: com.mysql.jdbc.Driver
12 | maxPoolSize: 100
13 | minPoolSize: 5
14 | username: root
15 | password: 123456
16 | type: com.alibaba.druid.pool.DruidDataSource
17 | url: jdbc:mysql://localhost:3306/tiktok?useUnicode=true&useSSL=false&allowPublicKeyRetrieval=true&characterEncoding=utf8
18 | # slaver数据库连接信息
19 | slaver0:
20 | driver-class-name: com.mysql.jdbc.Driver
21 | maxPoolSize: 100
22 | minPoolSize: 5
23 | username: root
24 | password: 123456
25 | type: com.alibaba.druid.pool.DruidDataSource
26 | url: jdbc:mysql://localhost:3307/tiktok?useUnicode=true&useSSL=false&allowPublicKeyRetrieval=true&characterEncoding=utf8
27 | # 配置数据源
28 | names: master0,slaver0
29 | # 显示sql
30 | props:
31 | sql:
32 | show: true
33 | # 配置默认数据源master 默认数据源,主要用于写
34 | sharding:
35 | default-database-strategy:
36 | inline:
37 | sharding-column: user_id
38 | algorithm-expression: master$->{user_id % 1}
39 | # 配置分表策略
40 | tables:
41 | comment:
42 | actual-data-nodes: master$->{0}.comment_$->{1..8}
43 | table-strategy:
44 | inline:
45 | sharding-column: comment_id
46 | algorithm-expression: comment_$->{comment_id % 8 + 1}
47 | favorite:
48 | actual-data-nodes: master$->{0}.favorite_$->{1..8}
49 | table-strategy:
50 | inline:
51 | sharding-column: favorite_id
52 | algorithm-expression: favorite_$->{favorite_id % 8 + 1}
53 | user_follows:
54 | actual-data-nodes: master$->{0}.user_follows_$->{1..4}
55 | table-strategy:
56 | inline:
57 | sharding-column: user_follows_id
58 | algorithm-expression: user_follows_$->{user_follows_id % 4 + 1}
59 | users:
60 | actual-data-nodes: master$->{0}.users_$->{1..2}
61 | table-strategy:
62 | inline:
63 | sharding-column: user_id
64 | algorithm-expression: users_$->{user_id % 2 + 1}
65 | video:
66 | actual-data-nodes: master$->{0}.video_$->{1..8}
67 | table-strategy:
68 | inline:
69 | sharding-column: video_id
70 | algorithm-expression: video_$->{video_id % 8 + 1}
71 | master-slave-rules:
72 | master0:
73 | master-data-source-name: master0
74 | slave-data-source-names: slaver0
75 | application:
76 | name: userservice
77 | mvc:
78 | static-path-pattern:server: /**
79 | cloud:
80 | # nacos相关地址
81 | nacos:
82 | server-addr: localhost:8848
83 | kafka:
84 | bootstrap-servers: localhost:9092
85 | consumer:
86 | group-id: test-consumer-group
87 | enable-auto-commit: true
88 | auto-commit-interval: 3000
89 |
90 | # 腾讯云发送短信的配置
91 | tencent:
92 | sms:
93 | secretId: yourSecretId
94 | secretKey: yourSecretKey
95 | endpoint: yourEndpoint
96 | region: yourRegion
97 | sdkAppId: yourSdkAppId
98 | signName: yourSignName
99 | templateId: yourTemplateId
100 | signMethod: "HmacSHA256"
101 |
102 | rabbitmq:
103 | # 生产者确认类型
104 | publisher-confirm-type: correlated
105 | publisher-returns: true
106 | template:
107 | mandatory: true
108 | host: localhost
109 | port: 5672
110 | username: root
111 | password: 123456
112 | virtual-host: / # 虚拟主机
113 | listener:
114 | direct:
115 | prefetch: 1 # 每个消费者每次只消费一条消息,不会出现高消费的情况,也就是承担不了那么多消息
116 | simple:
117 | # 消费者消息确认机制
118 | acknowledge-mode: auto
119 | retry:
120 | # 开启消费者失败重试
121 | enabled: true
122 | # 初始的失败等待时长为1秒
123 | initial-interval: 1000
124 | # 失败的等待时长倍数,下次等待时长 = multiplier * last-interval
125 | multiplier: 1
126 | # 最大重试次数
127 | max-attempts: 3
128 | # true无状态;false有状态。如果业务中包含事务,这里改为false
129 | stateless: false
130 | # 最大文件大小
131 | servlet:
132 | multipart:
133 | max-file-size: 100MB
134 | max-request-size: 100MB
135 | redis:
136 | host: localhost
137 | port: 6379
138 | lettuce:
139 | cluster:
140 | refresh:
141 | adaptive: true
142 | period: 600000
143 | pool:
144 | max-active: 8 # 连接池最大连接数
145 | max-wait: -1 # 最大阻塞等待时间没有限制
146 | min-idle: 0 # 连接池中最小空闲连接数
147 | timeout: 200 # 连接超时时间
148 | server:
149 | port: 9191
150 | # 缓存过期值随机打散(30分钟到60分钟)
151 | random_start: 30
152 | random_end: 60
153 |
154 | mybatis-plus:
155 | configuration:
156 | #在映射实体或者属性时,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射
157 | map-underscore-to-camel-case: true
158 | # 日志输出到控制台
159 | log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
160 | logging:
161 | level:
162 | # 这个包下的日志记录级别为debug
163 | com.zzzi: debug
164 | pattern:
165 | dateformat: MM-dd HH:mm:ss:SSS
166 | feign:
167 | httpclient:
168 | enabled: true # 支持HttpClient的开关
169 | max-connections: 200 # 最大连接数
170 | max-connections-per-route: 50 # 单个路径的最大连接数
171 | # 防止远程调用出错
172 | ribbon.nacos.enabled: true
--------------------------------------------------------------------------------
/user-service/src/main/resources/banner.txt:
--------------------------------------------------------------------------------
1 | ${AnsiColor.GREEN}
2 | ██╗ ██╗███████╗███████╗██████╗
3 | ██║ ██║██╔════╝██╔════╝██╔══██╗
4 | ██║ ██║███████╗█████╗ ██████╔╝
5 | ██║ ██║╚════██║██╔══╝ ██╔══██╗
6 | ╚██████╔╝███████║███████╗██║ ██║
7 | ╚═════╝ ╚══════╝╚══════╝╚═╝ ╚═╝
8 | ${AnsiColor.BRIGHT_BLACK}
--------------------------------------------------------------------------------
/user-service/src/test/java/com/zzzi/userservice/UserServiceApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.userservice;
2 |
3 | import com.alibaba.csp.sentinel.util.StringUtil;
4 | import com.zzzi.common.utils.JwtUtils;
5 | import com.zzzi.common.utils.MD5Utils;
6 | import org.apache.commons.lang.StringUtils;
7 | import org.junit.jupiter.api.Test;
8 | import org.springframework.boot.test.context.SpringBootTest;
9 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
10 |
11 | import java.util.UUID;
12 |
13 | //@SpringBootTest
14 | class UserServiceApplicationTests {
15 |
16 | @Test
17 | void contextLoads() {
18 | }
19 |
20 | /**
21 | * @author zzzi
22 | * @date 2024/3/27 13:57
23 | * 测试用户名和用户id一致时,前后生成的token是否一致
24 | */
25 | @Test
26 | void testToken() {
27 | Long userId = 1500000000000000000L;
28 | String userName = "123";
29 | String token1 = JwtUtils.createToken(userId, userName);
30 | String token2 = JwtUtils.createToken(userId, userName);
31 | System.out.println(token1);
32 | System.out.println(token2);
33 | System.out.println(token1.equals(token2));
34 | }
35 |
36 | @Test
37 | void testParseToken() {
38 | String token = "eyJhbGciOiJIUzUxMiIsInppcCI6IkdaSVAifQ.H4sIAAAAAAAAAKtWKi5NUrJSconUDQ12DVLSUUqtKFCyMjQ3NLSwsDAytdBRKi1OLfJMAYqZGqADiKRfYm4q0AhDI2OlWgAB1h9IUAAAAA.1S3xfjQNKSeR6ytrMN3tJBh9CkH4qOINVWMCAWXJZGJF5SzU6nMRyejpfLQbQ0iTQXrbjh_uN6UJKWRiMY28Ww";
39 | Long userIdByToken = JwtUtils.getUserIdByToken(token);
40 | System.out.println(userIdByToken);
41 | }
42 |
43 | @Test
44 | void testBCryptPasswordEncoder() {
45 | // Create an encoder with strength 16
46 | BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(16);
47 | String result = encoder.encode("123456");
48 | System.out.println(result);
49 | }
50 |
51 | @Test
52 | void testMD5Salt() {
53 | String passMD5 = MD5Utils.parseStrToMd5L32("123456");
54 | System.out.println(passMD5);
55 | }
56 |
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/video-service/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | *.yml
4 | !.mvn/wrapper/maven-wrapper.jar
5 | !**/src/main/**/target/
6 | !**/src/test/**/target/
7 |
8 | ### STS ###
9 | .apt_generated
10 | .classpath
11 | .factorypath
12 | .project
13 | .settings
14 | .springBeans
15 | .sts4-cache
16 |
17 | ### IntelliJ IDEA ###
18 | .idea
19 | *.iws
20 | *.iml
21 | *.ipr
22 |
23 | ### NetBeans ###
24 | /nbproject/private/
25 | /nbbuild/
26 | /dist/
27 | /nbdist/
28 | /.nb-gradle/
29 | build/
30 | !**/src/main/**/build/
31 | !**/src/test/**/build/
32 |
33 | ### VS Code ###
34 | .vscode/
35 |
--------------------------------------------------------------------------------
/video-service/src/main/java/com/zzzi/videoservice/VideoServiceApplication.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.videoservice;
2 |
3 | import com.alibaba.cloud.nacos.ribbon.NacosRule;
4 | import com.netflix.loadbalancer.IRule;
5 | import com.zzzi.common.config.DefaultFeignConfiguration;
6 | import com.zzzi.common.constant.RedisKeys;
7 | import com.zzzi.common.feign.UserClient;
8 | import lombok.extern.slf4j.Slf4j;
9 | import org.springframework.beans.factory.annotation.Autowired;
10 | import org.springframework.boot.SpringApplication;
11 | import org.springframework.boot.autoconfigure.SpringBootApplication;
12 | import org.springframework.cloud.openfeign.EnableFeignClients;
13 | import org.springframework.context.annotation.Bean;
14 | import org.springframework.context.annotation.EnableAspectJAutoProxy;
15 | import org.springframework.data.redis.core.StringRedisTemplate;
16 | import org.springframework.transaction.annotation.EnableTransactionManagement;
17 |
18 | import javax.annotation.PreDestroy;
19 | import java.util.Set;
20 |
21 | @SpringBootApplication(scanBasePackages = {"com.zzzi.*"})
22 | @EnableTransactionManagement//开启事务管理
23 | @EnableFeignClients(clients = UserClient.class, defaultConfiguration = DefaultFeignConfiguration.class)
24 | @EnableAspectJAutoProxy(exposeProxy = true)
25 | public class VideoServiceApplication {
26 |
27 | public static void main(String[] args) {
28 | SpringApplication.run(VideoServiceApplication.class, args);
29 | }
30 |
31 | //负载均衡规则
32 | @Bean
33 | public IRule rule() {
34 | return new NacosRule();
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/video-service/src/main/java/com/zzzi/videoservice/config/BinLogEventHandler.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.videoservice.config;
2 |
3 |
4 | import com.gitee.Jmysy.binlog4j.core.BinlogEvent;
5 | import com.gitee.Jmysy.binlog4j.core.IBinlogEventHandler;
6 | import com.gitee.Jmysy.binlog4j.springboot.starter.annotation.BinlogSubscriber;
7 | import com.zzzi.common.constant.RedisDefaultValue;
8 | import com.zzzi.common.constant.RedisKeys;
9 | import com.zzzi.videoservice.entity.VideoDO;
10 | import lombok.extern.slf4j.Slf4j;
11 | import org.springframework.beans.factory.annotation.Autowired;
12 | import org.springframework.beans.factory.annotation.Value;
13 | import org.springframework.data.redis.core.StringRedisTemplate;
14 |
15 | import java.util.List;
16 | import java.util.regex.Pattern;
17 |
18 | /**
19 | * @author zzzi
20 | * @date 2024/4/8 12:10
21 | * 在这里监听mysql中binlog的变化,从而完成缓存同步
22 | */
23 | @Slf4j
24 | @BinlogSubscriber(clientName = "master")
25 | public class BinLogEventHandler implements IBinlogEventHandler {
26 |
27 | @Autowired
28 | private StringRedisTemplate redisTemplate;
29 |
30 | @Value("${user_works_max_size}")
31 | public Long USER_WORKS_MAX_SIZE;
32 |
33 | @Override
34 | public void onInsert(BinlogEvent binlogEvent) {
35 | log.info("监听到视频表的插入");
36 | Long authorId = binlogEvent.getData().getAuthorId();
37 | Long videoId = binlogEvent.getData().getVideoId();
38 |
39 | //如果用户作品列表中有默认值,此时先删除默认值再添加
40 | List userWorkList = redisTemplate.opsForList().range(RedisKeys.USER_WORKS_PREFIX + authorId, 0, -1);
41 | if (userWorkList.contains(RedisDefaultValue.REDIS_DEFAULT_VALUE)) {
42 | log.info("删除用户作品列表缓存的默认值");
43 | redisTemplate.delete(RedisKeys.USER_WORKS_PREFIX + authorId);
44 | }
45 | //先插入当前投稿的作品信息
46 | redisTemplate.opsForList().leftPush(RedisKeys.USER_WORKS_PREFIX + authorId, videoId + "");
47 | while (redisTemplate.opsForList().size(RedisKeys.USER_WORKS_PREFIX + authorId) > USER_WORKS_MAX_SIZE) {
48 | //从右边删除,代表删除最早投稿的视频
49 | redisTemplate.opsForList().rightPop(RedisKeys.USER_WORKS_PREFIX + authorId);
50 | }
51 | }
52 |
53 | //todo:用户信息和视频信息更新后,尝试直接更新缓存
54 | @Override
55 | public void onUpdate(BinlogEvent binlogEvent) {
56 | log.info("监听到视频表的更新");
57 | VideoDO data = binlogEvent.getData();
58 |
59 | System.out.println(data);
60 | }
61 |
62 | @Override
63 | public void onDelete(BinlogEvent binlogEvent) {
64 | log.info("监听到视频表的删除");
65 | VideoDO data = binlogEvent.getData();
66 |
67 | System.out.println(data);
68 |
69 | }
70 |
71 | @Override
72 | public boolean isHandle(String s, String s1) {
73 | log.info("监听的数据库为:{},表名为:{}", s, s1);
74 | //变化的表是tiktok中的video_{1..8}是才触发当前handler的执行
75 | return s.equals("tiktok") && Pattern.matches("^video_[1-8]$", s1);
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/video-service/src/main/java/com/zzzi/videoservice/config/MyMetaObjectHandler.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.videoservice.config;
2 |
3 | import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
4 | import com.zzzi.common.exception.VideoException;
5 | import lombok.extern.slf4j.Slf4j;
6 | import org.apache.ibatis.reflection.MetaObject;
7 | import org.springframework.stereotype.Component;
8 |
9 | /**@author zzzi
10 | * @date 2024/3/27 19:25
11 | * 在这里进行基本的属性回显
12 | * 更加复杂的属性回显后期操作
13 | * 所有实体的内容都可以在这里重新赋值,相当于共用一个填充器
14 | */
15 | import java.time.LocalDateTime;
16 | import java.util.Date;
17 |
18 | @Component
19 | @Slf4j
20 | public class MyMetaObjectHandler implements MetaObjectHandler {
21 |
22 | @Override
23 | public void insertFill(MetaObject metaObject) {
24 | try {
25 | //todo 实体类的id使用雪花算法生成全局唯一ID
26 | this.strictInsertFill(metaObject, "createTime", Date.class, new Date());
27 | this.strictInsertFill(metaObject, "title", String.class, "抖音记录美好生活");
28 | //更新时间不管什么时候都自动更新
29 | this.strictInsertFill(metaObject, "updateTime", Date.class, new Date());
30 | this.strictInsertFill(metaObject, "favoriteCount", Integer.class, 0);
31 | this.strictInsertFill(metaObject, "commentCount", Integer.class, 0);
32 | } catch (Exception e) {
33 | log.error(e.getMessage());
34 | throw new VideoException("属性自动填充失败");
35 | }
36 | }
37 |
38 | @Override
39 | public void updateFill(MetaObject metaObject) {
40 | try {
41 | //更新时间不管如何都直接填充
42 | this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
43 | } catch (Exception e) {
44 | log.error(e.getMessage());
45 | throw new VideoException("属性自动填充失败");
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/video-service/src/main/java/com/zzzi/videoservice/config/MybatisPlusConfig.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.videoservice.config;
2 |
3 | import com.baomidou.mybatisplus.annotation.DbType;
4 | import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
5 | import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
6 | import org.springframework.context.annotation.Bean;
7 | import org.springframework.context.annotation.Configuration;
8 |
9 | /**
10 | * @author zzzi
11 | * @date 2024/4/2 17:07
12 | * 在这里配置分页插件
13 | */
14 | @Configuration
15 | public class MybatisPlusConfig {
16 |
17 | /**
18 | * 添加分页插件
19 | */
20 | @Bean
21 | public MybatisPlusInterceptor mybatisPlusInterceptor() {
22 | MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
23 | interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));//如果配置多个插件,切记分页最后添加
24 | return interceptor;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/video-service/src/main/java/com/zzzi/videoservice/config/RabbitMQConfig.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.videoservice.config;
2 |
3 | import com.zzzi.common.constant.RabbitMQKeys;
4 | import org.springframework.amqp.core.Binding;
5 | import org.springframework.amqp.core.BindingBuilder;
6 | import org.springframework.amqp.core.DirectExchange;
7 | import org.springframework.amqp.core.Queue;
8 | import org.springframework.amqp.rabbit.core.RabbitTemplate;
9 | import org.springframework.amqp.rabbit.retry.MessageRecoverer;
10 | import org.springframework.amqp.rabbit.retry.RepublishMessageRecoverer;
11 | import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
12 | import org.springframework.amqp.support.converter.MessageConverter;
13 | import org.springframework.context.annotation.Bean;
14 | import org.springframework.context.annotation.Configuration;
15 |
16 | /**
17 | * @author zzzi
18 | * @date 2024/3/27 16:24
19 | * 这可以使得RabbitMQ使用json序列化,而不是使用java中的jdk序列化
20 | */
21 | @Configuration
22 | public class RabbitMQConfig {
23 | @Bean
24 | public MessageConverter jsonMessageConverter() {
25 | return new Jackson2JsonMessageConverter();
26 | }
27 |
28 | /**
29 | * @author zzzi
30 | * @date 2024/4/4 19:09
31 | * 定义两个Work模式的队列,监听点赞消息,用来更新视频信息
32 | */
33 | @Bean
34 | public Queue createFavoriteVideoQueue() {
35 | return new Queue(RabbitMQKeys.FAVORITE_VIDEO);
36 | }
37 |
38 | @Bean
39 | public Queue createUnFavoriteVideoQueue() {
40 | return new Queue(RabbitMQKeys.UN_FAVORITE_VIDEO);
41 | }
42 |
43 | /**
44 | * @author zzzi
45 | * @date 2024/4/9 16:01
46 | * 消费者消费消息失败时会进行重试
47 | * 重试次数达到设置的上限时会将失败的消息投放到这个队列中
48 | */
49 |
50 | //定义错误消息的交换机
51 | @Bean
52 | public DirectExchange errorMessageExchange() {
53 | return new DirectExchange(RabbitMQKeys.ERROR_EXCHANGE);
54 | }
55 |
56 | //定义错误消息的队列
57 | @Bean
58 | public Queue errorQueue() {
59 | return new Queue("error.queue", true);
60 | }
61 |
62 | //定义二者之间的绑定关系
63 | @Bean
64 | public Binding errorBinding(Queue errorQueue, DirectExchange errorMessageExchange) {
65 | return BindingBuilder.bind(errorQueue).to(errorMessageExchange).with(RabbitMQKeys.ERROR);
66 | }
67 |
68 | @Bean
69 | public MessageRecoverer republishMessageRecoverer(RabbitTemplate rabbitTemplate) {
70 | //重试次数耗尽时,会将失败的消息发送给指定的队列
71 | return new RepublishMessageRecoverer(rabbitTemplate, RabbitMQKeys.ERROR_EXCHANGE, RabbitMQKeys.ERROR);
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/video-service/src/main/java/com/zzzi/videoservice/config/ReturnCallBack.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.videoservice.config;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.springframework.amqp.rabbit.core.RabbitTemplate;
5 | import org.springframework.beans.BeansException;
6 | import org.springframework.context.ApplicationContext;
7 | import org.springframework.context.ApplicationContextAware;
8 | import org.springframework.context.annotation.Configuration;
9 |
10 |
11 | @Configuration
12 | @Slf4j
13 | /**@author zzzi
14 | * @date 2024/4/9 15:24
15 | * 定义消息发送失败的回调
16 | * 消息到达交换机但是没有到达队列时触发
17 | */
18 | public class ReturnCallBack implements ApplicationContextAware {
19 | @Override
20 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
21 | // 获取RabbitTemplate
22 | RabbitTemplate rabbitTemplate = applicationContext.getBean(RabbitTemplate.class);
23 | // 设置ReturnCallback
24 | rabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routingKey) -> {
25 | // 投递失败,记录日志
26 | log.info("消息发送失败,应答码{},原因{},交换机{},路由键{},消息{}",
27 | replyCode, replyText, exchange, routingKey, message.toString());
28 | // 如果有业务需要,可以重发消息
29 | });
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/video-service/src/main/java/com/zzzi/videoservice/config/UnExpectedExitHandler.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.videoservice.config;
2 |
3 | import com.zzzi.common.constant.RedisKeys;
4 | import lombok.extern.slf4j.Slf4j;
5 | import org.springframework.beans.factory.DisposableBean;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.data.redis.core.StringRedisTemplate;
8 | import org.springframework.stereotype.Component;
9 |
10 | import java.util.Set;
11 |
12 | /**
13 | * @author zzzi
14 | * @date 2024/4/4 17:27
15 | * 程序意外退出执行这个方法
16 | */
17 | @Component
18 | @Slf4j
19 | public class UnExpectedExitHandler implements DisposableBean {
20 | @Autowired
21 | private StringRedisTemplate redisTemplate;
22 |
23 | /**
24 | * @author zzzi
25 | * @date 2024/4/4 17:22
26 | * 系统崩溃时删除所有用户token,防止token没过期下次登录不上
27 | */
28 | @Override
29 | public void destroy() throws Exception {
30 | boolean state = false;
31 | Set keys = redisTemplate.keys("*");
32 | for (String key : keys) {
33 | //只删除用户token
34 | if (key.startsWith(RedisKeys.USER_TOKEN_PREFIX))
35 | redisTemplate.delete(key);
36 | state = true;
37 | }
38 | if (state) {
39 | log.info("清除缓存成功!");
40 | } else {
41 | log.info("无缓存数据可清除!");
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/video-service/src/main/java/com/zzzi/videoservice/config/WebConfig.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.videoservice.config;
2 |
3 | import com.zzzi.videoservice.interceptor.LoginUserInterceptor;
4 | import org.springframework.context.annotation.Configuration;
5 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
6 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
7 |
8 | /**
9 | * @author zzzi
10 | * @date 2024/3/29 15:23
11 | * 给当前项目配置拦截器
12 | */
13 | @Configuration
14 | public class WebConfig implements WebMvcConfigurer {
15 |
16 | @Override
17 | public void addInterceptors(InterceptorRegistry registry) {
18 | // 只拦截需要 登录校验的请求.比如登录/评论/点赞/发布视频/用户关注/推送视频
19 | // 除了登录和获取资源还有推送视频不拦截,其他的都拦截
20 | registry.addInterceptor(new LoginUserInterceptor()).excludePathPatterns(
21 | "/douyin/user/**",//这里包括获取用户信息
22 | "/resource/**",
23 | "/douyin/feed/**"
24 | ).order(1);
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/video-service/src/main/java/com/zzzi/videoservice/controller/CommentController.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.videoservice.controller;
2 |
3 | import com.zzzi.common.result.CommentActionVO;
4 | import com.zzzi.common.result.CommentListVO;
5 | import com.zzzi.common.result.CommentVO;
6 | import com.zzzi.videoservice.service.CommentService;
7 | import lombok.extern.slf4j.Slf4j;
8 | import org.springframework.beans.factory.annotation.Autowired;
9 | import org.springframework.web.bind.annotation.*;
10 |
11 | import java.util.List;
12 |
13 | //评论模块
14 | @RestController
15 | @RequestMapping("/douyin/comment")
16 | @Slf4j
17 | public class CommentController {
18 |
19 | @Autowired
20 | private CommentService commentService;
21 |
22 | /**
23 | * @author zzzi
24 | * @date 2024/4/2 22:17
25 | * 获取视频评论列表
26 | * 这里的token应该不是必须的,没有登录的时候看视频评论,用户is_follow默认都是false,视频也没有点赞
27 | * 先当他是必须的
28 | */
29 | @GetMapping("/list")
30 | public CommentListVO getCommentList(String token, String video_id) {
31 | log.info("获取视频评论列表,token为:{},video_id为:{}", token, video_id);
32 | //截取真正的token
33 | if (token != null && token.startsWith("login:token:"))
34 | token = token.substring(12);
35 | List comment_list = commentService.getCommentList(token, video_id);
36 | if (comment_list != null) {
37 | return CommentListVO.success("获取评论列表成功", comment_list);
38 | }
39 | return CommentListVO.fail("获取评论列表失败");
40 | }
41 |
42 | /**
43 | * @author zzzi
44 | * @date 2024/5/5 20:35
45 | * 获取指定父评论的子评论(点击查看更多发的请求)
46 | */
47 | @GetMapping("/listParent")
48 | public CommentListVO getParentCommentList(String token, String parent_id) {
49 | log.info("获取视频评论列表,token为:{},parent_id为:{}", token, parent_id);
50 | //截取真正的token
51 | if (token != null && token.startsWith("login:token:"))
52 | token = token.substring(12);
53 | List comment_list = commentService.getParentCommentList(token, parent_id);
54 | if (comment_list != null) {
55 | return CommentListVO.success("获取父评论列表成功", comment_list);
56 | }
57 | return CommentListVO.fail("获取父评论列表失败");
58 | }
59 |
60 | /**
61 | * @author zzzi
62 | * @date 2024/5/5 16:17
63 | * 用户父子评论操作
64 | */
65 | @PostMapping("/action")
66 | public CommentActionVO commentParentAction(String token, String video_id, String action_type,
67 | @RequestParam(required = false) String comment_text,
68 | @RequestParam(required = false) String comment_id,
69 | @RequestParam(required = false) String parent_id,
70 | @RequestParam(required = false) String reply_id) {
71 | log.info("用户评论操作,token 为:{},video_id为:{},action_type为:{},comment_id为:{}", token, video_id, action_type, comment_id);
72 | //截取真正的token
73 | if (token.startsWith("login:token:"))
74 | token = token.substring(12);
75 | if ("1".equals(action_type)) {//评论操作
76 | CommentVO commentVO = commentService.commentParentAction(token, video_id, comment_text, parent_id, reply_id);
77 | return commentVO != null ? CommentActionVO.success("评论成功", commentVO) :
78 | CommentActionVO.fail("评论失败");
79 | } else {//删除评论操作
80 | CommentVO commentVO = commentService.commentParentUnAction(token, video_id, comment_id);
81 | return commentVO != null ? CommentActionVO.success("删除评论成功", commentVO) :
82 | CommentActionVO.fail("删除评论失败");
83 | }
84 | }
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/video-service/src/main/java/com/zzzi/videoservice/controller/FavoriteController.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.videoservice.controller;
2 |
3 | import com.alibaba.csp.sentinel.annotation.SentinelResource;
4 | import com.zzzi.common.result.CommonVO;
5 | import com.zzzi.common.result.VideoListVO;
6 | import com.zzzi.common.result.VideoVO;
7 | import com.zzzi.videoservice.service.FavoriteService;
8 | import lombok.extern.slf4j.Slf4j;
9 | import org.springframework.beans.factory.annotation.Autowired;
10 | import org.springframework.web.bind.annotation.GetMapping;
11 | import org.springframework.web.bind.annotation.PostMapping;
12 | import org.springframework.web.bind.annotation.RequestMapping;
13 | import org.springframework.web.bind.annotation.RestController;
14 |
15 | import java.util.List;
16 |
17 | //用户点赞的相关操作
18 | @RestController
19 | @RequestMapping("/douyin/favorite")
20 | @Slf4j
21 | public class FavoriteController {
22 |
23 | @Autowired
24 | private FavoriteService favoriteService;
25 |
26 | /**
27 | * @author zzzi
28 | * @date 2024/4/2 12:50
29 | * 用户点赞/取消点赞
30 | * 失败时会在service层报错
31 | */
32 | @PostMapping("/action")
33 | public CommonVO favoriteAction(String token, String video_id, String action_type) {
34 | log.info("用户点赞操作service,token为:{},video_id为:{},action_type为:{}", token, video_id, action_type);
35 | //截取真正的token
36 | if (token.startsWith("login:token:"))
37 | token = token.substring(12);
38 | String status_msg = "";
39 | if ("1".equals(action_type)) {
40 | log.info("用户点赞");
41 | favoriteService.favoriteAction(token, video_id);
42 | status_msg = "成功点赞";
43 | } else {
44 | log.info("用户取消点赞");
45 | favoriteService.favoriteUnAction(token, video_id);
46 | status_msg = "成功取消点赞";
47 | }
48 | return CommonVO.success(status_msg);
49 | }
50 |
51 | /**
52 | * @author zzzi
53 | * @date 2024/4/2 12:50
54 | * 获取用户喜欢列表
55 | */
56 | @SentinelResource("userFavorites")
57 | @GetMapping("/list")
58 | public VideoListVO getFavoriteList(String user_id, String token) {
59 | log.info("获取用户点赞列表,user_id为:{},token为:{}", user_id, token);
60 | //截取所有的token
61 | if (token != null && token.startsWith("login:token:"))
62 | token = token.substring(12);
63 | List videoVOList = favoriteService.getFavoriteList(user_id, token);
64 | if (videoVOList != null) {
65 | return VideoListVO.success("成功", videoVOList);
66 | }
67 | return VideoListVO.fail("获取用户点赞列表失败");
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/video-service/src/main/java/com/zzzi/videoservice/controller/VideoController.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.videoservice.controller;
2 |
3 | import com.alibaba.csp.sentinel.annotation.SentinelResource;
4 | import com.zzzi.common.result.CommonVO;
5 | import com.zzzi.common.result.VideoFeedListVO;
6 | import com.zzzi.common.result.VideoListVO;
7 | import com.zzzi.common.result.VideoVO;
8 | import com.zzzi.common.utils.MultiPartUploadUtils;
9 | import com.zzzi.videoservice.dto.VideoFeedDTO;
10 | import com.zzzi.videoservice.service.VideoService;
11 | import lombok.extern.slf4j.Slf4j;
12 | import org.springframework.beans.factory.annotation.Autowired;
13 | import org.springframework.web.bind.annotation.*;
14 | import org.springframework.web.multipart.MultipartFile;
15 |
16 | import javax.annotation.PostConstruct;
17 | import java.io.File;
18 | import java.io.IOException;
19 | import java.util.List;
20 | import java.util.UUID;
21 |
22 | @RestController
23 | @RequestMapping("/douyin")
24 | @Slf4j
25 | public class VideoController {
26 | @Autowired
27 | private VideoService videoService;
28 |
29 | /**
30 | * @author zzzi
31 | * @date 2024/3/28 14:13
32 | * 获取用户的所有作品
33 | * 由于作品信息更新时会删除缓存,所以可能需要缓存重构
34 | * 并且作品列表涉及到获取用户信息,所以需要远程调用
35 | */
36 | @SentinelResource("userWorks")
37 | @GetMapping("/publish/list")
38 | public VideoListVO getPublishList(String token, Long user_id) {
39 | log.info("获取用户投稿列表,token为:{},user_id为:{}", token, user_id);
40 | //截取真正的token,去掉前缀"login:token:"
41 | if (token.startsWith("login:token:"))
42 | token = token.substring(12);
43 | List videoVOList = videoService.getPublishListByAuthorId(token, user_id);
44 | if (videoVOList == null)
45 | return VideoListVO.fail("用户没有作品");
46 | return VideoListVO.success("成功", videoVOList);
47 | }
48 |
49 | /**
50 | * @author zzzi
51 | * @date 2024/3/29 12:14
52 | * 30个视频刷完按照这个当前推荐视频的最早时间继续推荐
53 | *
54 | * 没传latest_time,默认为最新时间
55 | * 推荐视频时,先拉取自己关注的大V的作品,然后拉取自己的收件箱中的视频
56 | * 二者结合得到推荐流
57 | * 1. 传递了token,先获取大V(拉模式),然后获取自己的关注(推模式)
58 | * 2. 没有传递token,先获取大V(拉模式),然后获取video数据集中最新的30个(推模式)
59 | */
60 | @GetMapping("/feed")
61 | public VideoFeedListVO getFeedList(@RequestParam(required = false) Long latest_time,
62 | @RequestParam(required = false) String token) {
63 | log.info("视频推荐,token为 :{}", token);
64 | //截取真正的token,去掉前缀"login:token:"
65 | if (token != null && token.startsWith("login:token:"))
66 | token = token.substring(12);
67 | /**@author zzzi
68 | * @date 2024/4/2 16:50
69 | * 时间没传,默认从当前时间向前推荐
70 | */
71 | if (latest_time == null)
72 | latest_time = System.currentTimeMillis();
73 | //默认下次也从当前时间开始推荐,这样视频少的时候可以循环推荐
74 | //根据是否传递token调用不同的方法
75 | VideoFeedDTO videoFeedDTO = null;
76 | if ("".equals(token) || token == null) {
77 | videoFeedDTO = videoService.getFeedListWithOutToken(latest_time);
78 | } else {
79 | videoFeedDTO = videoService.getFeedListWithToken(latest_time, token);
80 | }
81 | //判断返回结果的形式
82 | if (videoFeedDTO != null) {
83 | List videoVOList = videoFeedDTO.getFeed_list();
84 |
85 | //更新下次推荐时间
86 | Long next_time = videoFeedDTO.getNext_time();
87 | return VideoFeedListVO.success("获取推荐视频成功", next_time, videoVOList);
88 | }
89 | return VideoFeedListVO.fail("获取推荐视频失败");
90 | }
91 |
92 | /**
93 | * @author zzzi
94 | * @date 2024/3/27 14:44
95 | * 用户投稿视频
96 | * 可以根据用户的token解析出用户的userId
97 | */
98 | @PostMapping("/publish/action")
99 | public CommonVO postVideo(MultipartFile data, String token, String title) {
100 | log.info("用户投稿,token 为:{}", token);
101 | //截取真正的token,去掉前缀"login:token:"
102 | if (token.startsWith("login:token:"))
103 | token = token.substring(12);
104 | videoService.postVideo(data, token, title);
105 |
106 | //只要不出错误,说明成功投稿
107 | return CommonVO.success("投稿成功");
108 | }
109 |
110 | }
111 |
--------------------------------------------------------------------------------
/video-service/src/main/java/com/zzzi/videoservice/dto/VideoFeedDTO.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.videoservice.dto;
2 |
3 | import com.zzzi.common.result.VideoVO;
4 | import lombok.AllArgsConstructor;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 |
8 | import java.util.List;
9 |
10 | @Data
11 | @NoArgsConstructor
12 | @AllArgsConstructor
13 | public class VideoFeedDTO {
14 |
15 | private List feed_list;
16 | private Long next_time;
17 | }
18 |
--------------------------------------------------------------------------------
/video-service/src/main/java/com/zzzi/videoservice/entity/CommentDO.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.videoservice.entity;
2 |
3 | import com.baomidou.mybatisplus.annotation.FieldFill;
4 | import com.baomidou.mybatisplus.annotation.TableField;
5 | import com.baomidou.mybatisplus.annotation.TableId;
6 | import com.baomidou.mybatisplus.annotation.TableName;
7 | import com.baomidou.mybatisplus.extension.activerecord.Model;
8 | import lombok.AllArgsConstructor;
9 | import lombok.Data;
10 | import lombok.NoArgsConstructor;
11 |
12 | import java.util.Date;
13 |
14 | //视频评论实体类
15 | @Data
16 | @NoArgsConstructor
17 | @AllArgsConstructor
18 | @TableName("comment")
19 | public class CommentDO extends Model {
20 | @TableId
21 | private Long commentId;
22 | private Long userId;
23 | private String commentText;
24 | private Long videoId;
25 | @TableField(fill = FieldFill.INSERT)
26 | private Date createTime;
27 | private Long parentId;
28 | private Long replyId;
29 | }
30 |
--------------------------------------------------------------------------------
/video-service/src/main/java/com/zzzi/videoservice/entity/FavoriteDO.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.videoservice.entity;
2 |
3 |
4 | import com.baomidou.mybatisplus.annotation.TableId;
5 | import com.baomidou.mybatisplus.annotation.TableName;
6 | import com.baomidou.mybatisplus.extension.activerecord.Model;
7 | import lombok.AllArgsConstructor;
8 | import lombok.Data;
9 | import lombok.NoArgsConstructor;
10 |
11 | //用户关注实体类
12 | @Data
13 | @NoArgsConstructor
14 | @AllArgsConstructor
15 | @TableName("favorite")
16 | public class FavoriteDO extends Model {
17 | @TableId
18 | private Long favoriteId;
19 | //谁点赞
20 | private Long userId;
21 | //哪个视频被点赞
22 | private Long videoId;
23 | }
24 |
--------------------------------------------------------------------------------
/video-service/src/main/java/com/zzzi/videoservice/entity/VideoDO.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.videoservice.entity;
2 |
3 | import com.baomidou.mybatisplus.annotation.FieldFill;
4 | import com.baomidou.mybatisplus.annotation.TableField;
5 | import com.baomidou.mybatisplus.annotation.TableId;
6 | import com.baomidou.mybatisplus.annotation.TableName;
7 | import com.baomidou.mybatisplus.extension.activerecord.Model;
8 | import lombok.AllArgsConstructor;
9 | import lombok.Data;
10 | import lombok.NoArgsConstructor;
11 |
12 | import java.util.Date;
13 |
14 | @Data
15 | @NoArgsConstructor
16 | @AllArgsConstructor
17 | @TableName("video")
18 | public class VideoDO extends Model {
19 | @TableId
20 | private Long videoId;
21 |
22 | private Long authorId;
23 |
24 | private String coverUrl;
25 |
26 | private String playUrl;
27 |
28 | @TableField(fill = FieldFill.INSERT)
29 | private Date createTime;
30 |
31 | @TableField(fill = FieldFill.INSERT_UPDATE)
32 | private Date updateTime;
33 |
34 | @TableField(fill = FieldFill.INSERT)
35 | private String title;
36 |
37 | @TableField(fill = FieldFill.INSERT)
38 | private Integer favoriteCount;
39 |
40 | @TableField(fill = FieldFill.INSERT)
41 | private Integer commentCount;
42 |
43 | }
44 |
45 |
--------------------------------------------------------------------------------
/video-service/src/main/java/com/zzzi/videoservice/interceptor/GlobalExceptionHandler.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.videoservice.interceptor;
2 |
3 | import com.zzzi.common.exception.*;
4 | import com.zzzi.common.result.CommentActionVO;
5 | import com.zzzi.common.result.CommentListVO;
6 | import com.zzzi.common.result.CommonVO;
7 | import com.zzzi.common.result.VideoListVO;
8 | import lombok.extern.slf4j.Slf4j;
9 | import org.springframework.web.bind.annotation.ControllerAdvice;
10 | import org.springframework.web.bind.annotation.ExceptionHandler;
11 | import org.springframework.web.bind.annotation.ResponseBody;
12 | import org.springframework.web.bind.annotation.RestController;
13 |
14 | import javax.security.auth.login.LoginException;
15 |
16 |
17 | /**
18 | * @author zzzi
19 | * @date 2024/3/26 22:34
20 | * 在这里处理videoservice中的所有异常
21 | */
22 | @ControllerAdvice(annotations = {RestController.class})
23 | @ResponseBody
24 | @Slf4j
25 | public class GlobalExceptionHandler {
26 |
27 | @ExceptionHandler(VideoException.class)
28 | public CommonVO VideoExceptionHandler(VideoException ex) {
29 | log.error(ex.getMessage());
30 |
31 | if (ex.getMessage().contains("视频上传失败")) {
32 | return CommonVO.fail("视频上传失败");
33 | }
34 |
35 | if (ex.getMessage().contains("视频保存失败")) {
36 | return CommonVO.fail("视频保存失败");
37 | }
38 | if (ex.getMessage().contains("属性自动填充失败")) {
39 | return CommonVO.fail("属性自动填充失败");
40 | }
41 | if (ex.getMessage().contains("视频已经存在")) {
42 | return CommonVO.fail("视频已经存在");
43 | }
44 |
45 | if (ex.getMessage().contains("获取用户作品列表失败")) {
46 | return CommonVO.fail("获取用户作品列表失败");
47 | }
48 |
49 | if (ex.getMessage().contains("当前用户未登录")) {
50 | return CommonVO.fail("当前用户未登录");
51 | }
52 | if (ex.getMessage().contains("更新视频信息失败")) {
53 | return CommonVO.fail("更新视频信息失败");
54 | }
55 | return CommonVO.fail("未知错误");
56 | }
57 |
58 | @ExceptionHandler(UserException.class)
59 | public CommonVO UserExceptionHandler(UserException ex) {
60 | log.error(ex.getMessage());
61 |
62 | if (ex.getMessage().contains("当前用户未登录")) {
63 | return CommonVO.fail("当前用户未登录");
64 | }
65 | return CommonVO.fail("未知错误");
66 | }
67 |
68 | @ExceptionHandler(LoginException.class)
69 | public CommonVO LoginExceptionHandler(LoginException ex) {
70 | log.error(ex.getMessage());
71 | return CommonVO.fail("请先登录");
72 | }
73 |
74 | @ExceptionHandler(Exception.class)
75 | public CommonVO CommonExceptionHandler(Exception ex) {
76 | log.error(ex.getMessage());
77 | return CommonVO.fail("未知错误");
78 | }
79 |
80 | @ExceptionHandler(VideoListException.class)
81 | public VideoListVO VideoListExceptionHandler(VideoListException ex) {
82 | log.error(ex.getMessage());
83 | if (ex.getMessage().contains("当前用户未登录")) {
84 | return VideoListVO.fail("当前用户未登录");
85 | }
86 | if (ex.getMessage().contains("获取用户作品列表失败")) {
87 | return VideoListVO.fail("获取用户作品列表失败");
88 | }
89 | if (ex.getMessage().contains("获取用户喜欢列表失败")) {
90 | return VideoListVO.fail("获取用户喜欢列表失败");
91 | }
92 | return VideoListVO.fail("未知错误");
93 | }
94 |
95 | @ExceptionHandler(CommentActionException.class)
96 | public CommentActionVO CommentActionExceptionHandler(CommentActionException ex) {
97 | log.error(ex.getMessage());
98 | if (ex.getMessage().contains("用户评论失败")) {
99 | return CommentActionVO.fail("用户评论失败");
100 | }
101 | if (ex.getMessage().contains("用户删除评论失败")) {
102 | return CommentActionVO.fail("用户删除评论失败");
103 | }
104 | return CommentActionVO.fail("未知错误");
105 | }
106 |
107 | @ExceptionHandler(CommentListException.class)
108 | public CommentListVO CommentListExceptionHandler(CommentListException ex) {
109 | log.error(ex.getMessage());
110 | if (ex.getMessage().contains("获取当前视频评论列表失败")) {
111 | return CommentListVO.fail("获取当前视频评论列表失败");
112 | }
113 | return CommentListVO.fail("未知错误");
114 | }
115 |
116 | @ExceptionHandler(RuntimeException.class)
117 | public CommonVO CommentListExceptionHandler(RuntimeException ex) {
118 | log.error(ex.getMessage());
119 | if (ex.getMessage().contains("请勿重复点赞")) {
120 | return CommonVO.fail("请勿重复点赞");
121 | }
122 | if (ex.getMessage().contains("用户点赞失败")) {
123 | return CommonVO.fail("用户点赞失败");
124 | }
125 | return CommonVO.fail("未知错误");
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/video-service/src/main/java/com/zzzi/videoservice/interceptor/LoginUserInterceptor.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.videoservice.interceptor;
2 |
3 | import com.alibaba.fastjson.JSONObject;
4 | import com.zzzi.common.constant.RedisKeys;
5 | import com.zzzi.common.result.CommonVO;
6 | import com.zzzi.common.utils.JwtUtils;
7 | import lombok.extern.slf4j.Slf4j;
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 | import org.springframework.beans.factory.annotation.Autowired;
11 | import org.springframework.data.redis.core.StringRedisTemplate;
12 | import org.springframework.stereotype.Component;
13 | import org.springframework.util.AntPathMatcher;
14 | import org.springframework.web.servlet.HandlerInterceptor;
15 |
16 | import javax.security.auth.login.LoginException;
17 | import javax.servlet.http.HttpServletRequest;
18 | import javax.servlet.http.HttpServletResponse;
19 |
20 | /**
21 | * @author zzzi
22 | * @date 2024/3/29 14:52
23 | * 不需要拦截的请求直接放行
24 | */
25 | @Component
26 | @Slf4j
27 | public class LoginUserInterceptor implements HandlerInterceptor {
28 | @Autowired
29 | private StringRedisTemplate redisTemplate;
30 |
31 | //除了视频推流,其余的请求都要带上token,否则拦截
32 | @Override
33 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
34 | // 放行无需登录的请求
35 | String uri = request.getRequestURI();
36 | AntPathMatcher antPathMatcher = new AntPathMatcher();// 匹配器
37 | boolean feed = antPathMatcher.match("/douyin/feed/**", uri);// 视频流
38 | log.info("登录拦截请求:" + uri);
39 | //放行无需登录的请求
40 | if (feed) {
41 | log.info("视频推流请求无需拦截");
42 | return true;
43 | }
44 |
45 | // 验证登录状态
46 | /**@author zzzi
47 | * @date 2024/3/29 14:53
48 | * 直接根据缓存中是否存在用户的token来判断
49 | * 为了调试方便,先全部放行
50 | */
51 | String token = request.getParameter("token");
52 | //log.info("拦截到的请求中,token为:{}", token);
53 | ////截取得到真正的token
54 | //if (token != null && !"".equals(token)) {
55 | // token = token.substring(12);
56 | //}
57 | ////没有抛异常的话就是验签成功
58 | //Long userId = JwtUtils.getUserIdByToken(token);
59 | //String userToken = redisTemplate.opsForValue().get(RedisKeys.USER_TOKEN_PREFIX + userId);
60 | //if (userToken == null || "".equals(userToken)) {
61 | // log.error("用户未登录,非法请求");
62 | // CommonVO fail = CommonVO.fail("请先登录");
63 | // String failString = JSONObject.toJSONString(fail);
64 | // response.getWriter().write(failString);
65 | // return false;
66 | //}
67 | return true;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/video-service/src/main/java/com/zzzi/videoservice/listener/CommentListener.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.videoservice.listener;
2 |
3 | import ch.qos.logback.core.joran.conditional.ThenOrElseActionBase;
4 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
5 | import com.google.gson.Gson;
6 | import com.zzzi.common.constant.RabbitMQKeys;
7 | import com.zzzi.common.exception.CommentActionException;
8 | import com.zzzi.videoservice.entity.VideoDO;
9 | import com.zzzi.videoservice.mapper.VideoMapper;
10 | import com.zzzi.common.utils.UpdateVideoInfoUtils;
11 | import lombok.extern.slf4j.Slf4j;
12 | import org.springframework.amqp.core.ExchangeTypes;
13 | import org.springframework.amqp.rabbit.annotation.Exchange;
14 | import org.springframework.amqp.rabbit.annotation.Queue;
15 | import org.springframework.amqp.rabbit.annotation.QueueBinding;
16 | import org.springframework.amqp.rabbit.annotation.RabbitListener;
17 | import org.springframework.aop.framework.AopContext;
18 | import org.springframework.beans.factory.annotation.Autowired;
19 | import org.springframework.messaging.handler.annotation.Payload;
20 | import org.springframework.stereotype.Service;
21 | import org.springframework.transaction.annotation.Transactional;
22 |
23 |
24 | @Service
25 | @Slf4j
26 | public class CommentListener {
27 |
28 | @Autowired
29 | private VideoMapper videoMapper;
30 | @Autowired
31 | private UpdateVideoInfoUtils updateVideoInfoUtils;
32 | @Autowired
33 | private Gson gson;
34 |
35 | @RabbitListener(
36 | bindings = @QueueBinding(
37 | value = @Queue(name = "direct.comment"),
38 | exchange = @Exchange(name = RabbitMQKeys.COMMENT_EXCHANGE, type = ExchangeTypes.DIRECT),
39 | key = {RabbitMQKeys.COMMENT_KEY}
40 | )
41 | )
42 | @Transactional
43 | public void listenToComment(@Payload long videoId) {
44 | log.info("监听到用户评论操作");
45 |
46 | //更新视频评论数
47 | VideoDO videoDO = videoMapper.selectById(videoId);
48 | Integer commentCount = videoDO.getCommentCount();
49 | //加上乐观锁
50 | LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
51 | queryWrapper.eq(VideoDO::getCommentCount, commentCount);
52 | videoDO.setCommentCount(commentCount + 1);
53 | int update = videoMapper.update(videoDO, queryWrapper);
54 | //更新失败说明出现线程安全问题,此时评论失败
55 | if (update != 1) {
56 | CommentListener commentListener = (CommentListener) AopContext.currentProxy();
57 | commentListener.listenToComment(videoId);
58 | }
59 |
60 | //更新视频缓存
61 | String videoDOJson = gson.toJson(videoDO);
62 | updateVideoInfoUtils.updateVideoInfoCache(videoId, videoDOJson);
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/video-service/src/main/java/com/zzzi/videoservice/listener/FavoriteListenerOne.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.videoservice.listener;
2 |
3 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
4 | import com.google.gson.Gson;
5 | import com.zzzi.common.constant.RabbitMQKeys;
6 | import com.zzzi.common.exception.VideoException;
7 | import com.zzzi.videoservice.entity.VideoDO;
8 | import com.zzzi.videoservice.mapper.VideoMapper;
9 | import com.zzzi.common.utils.UpdateVideoInfoUtils;
10 | import lombok.extern.slf4j.Slf4j;
11 | import org.springframework.amqp.rabbit.annotation.RabbitListener;
12 | import org.springframework.aop.framework.AopContext;
13 | import org.springframework.beans.factory.annotation.Autowired;
14 | import org.springframework.messaging.handler.annotation.Payload;
15 | import org.springframework.stereotype.Service;
16 | import org.springframework.transaction.annotation.Transactional;
17 | import sun.awt.geom.AreaOp;
18 |
19 |
20 | /**
21 | * @author zzzi
22 | * @date 2024/3/29 16:38
23 | * 在这里异步的更新视频的基本信息
24 | */
25 | @Service
26 | @Slf4j
27 | public class FavoriteListenerOne {
28 | @Autowired
29 | private VideoMapper videoMapper;
30 | @Autowired
31 | private UpdateVideoInfoUtils updateVideoInfoUtils;
32 | @Autowired
33 | private Gson gson;
34 |
35 | @RabbitListener(queues = {RabbitMQKeys.FAVORITE_VIDEO})
36 | @Transactional
37 | public void listenToFavorite(@Payload long videoId) {
38 | log.info("第一个消费者监听到用户点赞操作");
39 |
40 | //更新视频点赞数
41 | VideoDO videoDO = videoMapper.selectById(videoId);
42 | Integer favoriteCount = videoDO.getFavoriteCount();
43 | LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
44 | //加上乐观锁
45 | queryWrapper.eq(VideoDO::getFavoriteCount, favoriteCount);
46 | videoDO.setFavoriteCount(favoriteCount + 1);
47 | int update = videoMapper.update(videoDO, queryWrapper);
48 | if (update != 1) {
49 | //手动实现CAS算法
50 | FavoriteListenerOne favoriteListener = (FavoriteListenerOne) AopContext.currentProxy();
51 | favoriteListener.listenToFavorite(videoId);
52 | }
53 |
54 | //更新视频缓存
55 | String videoDOJson = gson.toJson(videoDO);
56 | updateVideoInfoUtils.updateVideoInfoCache(videoId, videoDOJson);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/video-service/src/main/java/com/zzzi/videoservice/listener/FavoriteListenerTwo.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.videoservice.listener;
2 |
3 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
4 | import com.google.gson.Gson;
5 | import com.zzzi.common.constant.RabbitMQKeys;
6 | import com.zzzi.common.exception.VideoException;
7 | import com.zzzi.videoservice.entity.VideoDO;
8 | import com.zzzi.videoservice.mapper.VideoMapper;
9 | import com.zzzi.common.utils.UpdateVideoInfoUtils;
10 | import lombok.extern.slf4j.Slf4j;
11 | import org.springframework.amqp.rabbit.annotation.RabbitListener;
12 | import org.springframework.aop.framework.AopContext;
13 | import org.springframework.beans.factory.annotation.Autowired;
14 | import org.springframework.messaging.handler.annotation.Payload;
15 | import org.springframework.stereotype.Service;
16 | import org.springframework.transaction.annotation.Transactional;
17 |
18 |
19 | /**
20 | * @author zzzi
21 | * @date 2024/3/29 16:38
22 | * 在这里异步的更新视频的基本信息
23 | */
24 | @Service
25 | @Slf4j
26 | public class FavoriteListenerTwo {
27 | @Autowired
28 | private VideoMapper videoMapper;
29 | @Autowired
30 | private UpdateVideoInfoUtils updateVideoInfoUtils;
31 | @Autowired
32 | private Gson gson;
33 |
34 | @RabbitListener(queues = {RabbitMQKeys.FAVORITE_VIDEO})
35 | @Transactional
36 | public void listenToFavorite(@Payload long videoId) {
37 | log.info("第二个消费者监听到用户点赞操作");
38 |
39 | //更新视频点赞数
40 | VideoDO videoDO = videoMapper.selectById(videoId);
41 | Integer favoriteCount = videoDO.getFavoriteCount();
42 | LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
43 | //加上乐观锁
44 | queryWrapper.eq(VideoDO::getFavoriteCount, favoriteCount);
45 | videoDO.setFavoriteCount(favoriteCount + 1);
46 | int update = videoMapper.update(videoDO, queryWrapper);
47 | if (update != 1) {
48 | //手动实现CAS算法
49 | FavoriteListenerTwo favoriteListener = (FavoriteListenerTwo) AopContext.currentProxy();
50 | favoriteListener.listenToFavorite(videoId);
51 | }
52 |
53 | //更新视频缓存
54 | String videoDOJson = gson.toJson(videoDO);
55 | updateVideoInfoUtils.updateVideoInfoCache(videoId, videoDOJson);
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/video-service/src/main/java/com/zzzi/videoservice/listener/UnCommentListener.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.videoservice.listener;
2 |
3 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
4 | import com.google.gson.Gson;
5 | import com.zzzi.common.constant.RabbitMQKeys;
6 | import com.zzzi.common.exception.CommentActionException;
7 | import com.zzzi.videoservice.entity.VideoDO;
8 | import com.zzzi.videoservice.mapper.VideoMapper;
9 | import com.zzzi.common.utils.UpdateVideoInfoUtils;
10 | import lombok.extern.slf4j.Slf4j;
11 | import org.springframework.amqp.core.ExchangeTypes;
12 | import org.springframework.amqp.rabbit.annotation.Exchange;
13 | import org.springframework.amqp.rabbit.annotation.Queue;
14 | import org.springframework.amqp.rabbit.annotation.QueueBinding;
15 | import org.springframework.amqp.rabbit.annotation.RabbitListener;
16 | import org.springframework.aop.framework.AopContext;
17 | import org.springframework.beans.factory.annotation.Autowired;
18 | import org.springframework.messaging.handler.annotation.Payload;
19 | import org.springframework.stereotype.Service;
20 | import org.springframework.transaction.annotation.Transactional;
21 |
22 |
23 | @Service
24 | @Slf4j
25 | public class UnCommentListener {
26 |
27 | @Autowired
28 | private VideoMapper videoMapper;
29 | @Autowired
30 | private UpdateVideoInfoUtils updateVideoInfoUtils;
31 | @Autowired
32 | private Gson gson;
33 |
34 | @RabbitListener(
35 | bindings = @QueueBinding(
36 | value = @Queue(name = "direct.un_comment"),
37 | exchange = @Exchange(name = RabbitMQKeys.COMMENT_EXCHANGE, type = ExchangeTypes.DIRECT),
38 | key = {RabbitMQKeys.UN_COMMENT_KEY}
39 | )
40 | )
41 | @Transactional
42 | public void listenToUnComment(@Payload long videoId) {
43 | log.info("监听到用户删除评论操作");
44 |
45 | //更新视频评论数数
46 | VideoDO videoDO = videoMapper.selectById(videoId);
47 | Integer commentCount = videoDO.getCommentCount();
48 | LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
49 | //加上乐观锁
50 | queryWrapper.eq(VideoDO::getCommentCount, commentCount);
51 | videoDO.setCommentCount(commentCount - 1);
52 | int update = videoMapper.update(videoDO, queryWrapper);
53 | if (update != 1) {
54 | //手动实现CAS算法
55 | UnCommentListener unCommentListener = (UnCommentListener) AopContext.currentProxy();
56 | unCommentListener.listenToUnComment(videoId);
57 | }
58 |
59 | //更新视频缓存
60 | String videoDOJson = gson.toJson(videoDO);
61 | updateVideoInfoUtils.updateVideoInfoCache(videoId, videoDOJson);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/video-service/src/main/java/com/zzzi/videoservice/listener/UnFavoriteListenerOne.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.videoservice.listener;
2 |
3 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
4 | import com.google.gson.Gson;
5 | import com.zzzi.common.constant.RabbitMQKeys;
6 | import com.zzzi.common.exception.VideoException;
7 | import com.zzzi.videoservice.entity.VideoDO;
8 | import com.zzzi.videoservice.mapper.VideoMapper;
9 | import com.zzzi.common.utils.UpdateVideoInfoUtils;
10 | import lombok.extern.slf4j.Slf4j;
11 | import org.springframework.amqp.rabbit.annotation.RabbitListener;
12 | import org.springframework.aop.framework.AopContext;
13 | import org.springframework.beans.factory.annotation.Autowired;
14 | import org.springframework.messaging.handler.annotation.Payload;
15 | import org.springframework.stereotype.Service;
16 | import org.springframework.transaction.annotation.Transactional;
17 |
18 |
19 | /**
20 | * @author zzzi
21 | * @date 2024/3/29 16:38
22 | * 在这里异步的更新用户的基本信息
23 | */
24 | @Service
25 | @Slf4j
26 | public class UnFavoriteListenerOne {
27 | @Autowired
28 | private VideoMapper videoMapper;
29 | @Autowired
30 | private UpdateVideoInfoUtils updateVideoInfoUtils;
31 | @Autowired
32 | private Gson gson;
33 |
34 |
35 | /**
36 | * @author zzzi
37 | * @date 2024/4/2 13:24
38 | * 在这里更新对应的视频信息
39 | */
40 | @RabbitListener(queues = {RabbitMQKeys.UN_FAVORITE_VIDEO})
41 | @Transactional
42 | public void listenToUnFavorite(@Payload long videoId) {
43 | log.info("第一个消费者监听到用户取消点赞操作");
44 | //更新视频点赞数
45 | VideoDO videoDO = videoMapper.selectById(videoId);
46 | Integer favoriteCount = videoDO.getFavoriteCount();
47 | LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
48 | //加上乐观锁
49 | queryWrapper.eq(VideoDO::getFavoriteCount, favoriteCount);
50 | videoDO.setFavoriteCount(favoriteCount - 1);
51 | int update = videoMapper.update(videoDO, queryWrapper);
52 | if (update != 1) {
53 | //手动实现CAS算法
54 | UnFavoriteListenerOne unFavoriteListener = (UnFavoriteListenerOne) AopContext.currentProxy();
55 | unFavoriteListener.listenToUnFavorite(videoId);
56 | }
57 |
58 | //更新视频缓存
59 | String videoDOJson = gson.toJson(videoDO);
60 | updateVideoInfoUtils.updateVideoInfoCache(videoId, videoDOJson);
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/video-service/src/main/java/com/zzzi/videoservice/listener/UnFavoriteListenerTwo.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.videoservice.listener;
2 |
3 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
4 | import com.google.gson.Gson;
5 | import com.zzzi.common.constant.RabbitMQKeys;
6 | import com.zzzi.common.exception.VideoException;
7 | import com.zzzi.videoservice.entity.VideoDO;
8 | import com.zzzi.videoservice.mapper.VideoMapper;
9 | import com.zzzi.common.utils.UpdateVideoInfoUtils;
10 | import lombok.extern.slf4j.Slf4j;
11 | import org.springframework.amqp.rabbit.annotation.RabbitListener;
12 | import org.springframework.aop.framework.AopContext;
13 | import org.springframework.beans.factory.annotation.Autowired;
14 | import org.springframework.messaging.handler.annotation.Payload;
15 | import org.springframework.stereotype.Service;
16 | import org.springframework.transaction.annotation.Transactional;
17 |
18 |
19 | /**
20 | * @author zzzi
21 | * @date 2024/3/29 16:38
22 | * 在这里异步的更新用户的基本信息
23 | */
24 | @Service
25 | @Slf4j
26 | public class UnFavoriteListenerTwo {
27 | @Autowired
28 | private VideoMapper videoMapper;
29 | @Autowired
30 | private UpdateVideoInfoUtils updateVideoInfoUtils;
31 | @Autowired
32 | private Gson gson;
33 |
34 | /**
35 | * @author zzzi
36 | * @date 2024/4/2 13:24
37 | * 在这里更新对应的视频信息
38 | */
39 | @RabbitListener(queues = {RabbitMQKeys.UN_FAVORITE_VIDEO})
40 | @Transactional
41 | public void listenToUnFavorite(@Payload long videoId) {
42 | log.info("第二个消费者监听到用户取消点赞操作");
43 | //更新视频点赞数
44 | VideoDO videoDO = videoMapper.selectById(videoId);
45 | Integer favoriteCount = videoDO.getFavoriteCount();
46 | LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
47 | //加上乐观锁
48 | queryWrapper.eq(VideoDO::getFavoriteCount, favoriteCount);
49 | videoDO.setFavoriteCount(favoriteCount - 1);
50 | int update = videoMapper.update(videoDO, queryWrapper);
51 | if (update != 1) {
52 | //手动实现CAS算法
53 | UnFavoriteListenerTwo unFavoriteListener = (UnFavoriteListenerTwo) AopContext.currentProxy();
54 | unFavoriteListener.listenToUnFavorite(videoId);
55 | }
56 |
57 | //更新视频缓存
58 | String videoDOJson = gson.toJson(videoDO);
59 | updateVideoInfoUtils.updateVideoInfoCache(videoId, videoDOJson);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/video-service/src/main/java/com/zzzi/videoservice/mapper/CommentMapper.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.videoservice.mapper;
2 |
3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
4 | import com.zzzi.videoservice.entity.CommentDO;
5 | import org.apache.ibatis.annotations.Mapper;
6 |
7 | @Mapper
8 | public interface CommentMapper extends BaseMapper {
9 | }
10 |
--------------------------------------------------------------------------------
/video-service/src/main/java/com/zzzi/videoservice/mapper/FavoriteMapper.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.videoservice.mapper;
2 |
3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
4 | import com.zzzi.videoservice.entity.FavoriteDO;
5 | import org.apache.ibatis.annotations.Mapper;
6 |
7 | @Mapper
8 | public interface FavoriteMapper extends BaseMapper {
9 | }
10 |
--------------------------------------------------------------------------------
/video-service/src/main/java/com/zzzi/videoservice/mapper/VideoMapper.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.videoservice.mapper;
2 |
3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
4 | import com.zzzi.videoservice.entity.VideoDO;
5 | import org.apache.ibatis.annotations.Mapper;
6 |
7 | @Mapper
8 | public interface VideoMapper extends BaseMapper {
9 | }
10 |
--------------------------------------------------------------------------------
/video-service/src/main/java/com/zzzi/videoservice/service/CommentService.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.videoservice.service;
2 |
3 | import com.baomidou.mybatisplus.extension.service.IService;
4 | import com.zzzi.common.result.CommentVO;
5 | import com.zzzi.common.result.CommonVO;
6 | import com.zzzi.videoservice.entity.CommentDO;
7 |
8 | import java.util.List;
9 |
10 | public interface CommentService extends IService {
11 | List getCommentList(String token, String video_id);
12 |
13 | CommentVO commentParentAction(String token, String video_id, String comment_text, String parent_id,String reply_id);
14 |
15 | CommentVO commentParentUnAction(String token, String video_id, String comment_id);
16 |
17 | List getParentCommentList(String token, String parent_id);
18 | }
19 |
--------------------------------------------------------------------------------
/video-service/src/main/java/com/zzzi/videoservice/service/FavoriteService.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.videoservice.service;
2 |
3 | import com.baomidou.mybatisplus.extension.service.IService;
4 | import com.zzzi.videoservice.entity.FavoriteDO;
5 | import com.zzzi.common.result.VideoVO;
6 |
7 | import java.util.List;
8 |
9 | public interface FavoriteService extends IService {
10 | void favoriteAction(String token, String video_id);
11 |
12 | void favoriteUnAction(String token, String video_id);
13 |
14 | List getFavoriteList(String user_id, String token);
15 | }
16 |
--------------------------------------------------------------------------------
/video-service/src/main/java/com/zzzi/videoservice/service/VideoService.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.videoservice.service;
2 |
3 | import com.baomidou.mybatisplus.extension.service.IService;
4 | import com.zzzi.common.result.UserVO;
5 | import com.zzzi.videoservice.dto.VideoFeedDTO;
6 | import com.zzzi.videoservice.entity.VideoDO;
7 | import com.zzzi.common.result.VideoVO;
8 | import org.springframework.web.multipart.MultipartFile;
9 |
10 | import java.util.List;
11 |
12 |
13 | public interface VideoService extends IService {
14 | void postVideo(MultipartFile data, String token, String title);
15 |
16 | List getPublishListByAuthorId(String token, Long user_id);
17 |
18 | //VideoFeedDTO getFeedList(Long latest_time, String token);
19 |
20 | VideoDO getVideoInfo(String videoId);
21 |
22 | VideoVO packageVideoVO(VideoDO videoDO, UserVO userVO, String user_id, String token);
23 |
24 | VideoVO packageFavoriteVideoVO(VideoDO videoDO, UserVO userVO);
25 |
26 | VideoFeedDTO getFeedListWithOutToken(Long latest_time);
27 |
28 | VideoFeedDTO getFeedListWithToken(Long latest_time, String token);
29 | }
30 |
--------------------------------------------------------------------------------
/video-service/src/main/resources/banner.txt:
--------------------------------------------------------------------------------
1 | ${AnsiColor.GREEN}
2 | ██╗ ██╗██╗██████╗ ███████╗ ██████╗
3 | ██║ ██║██║██╔══██╗██╔════╝██╔═══██╗
4 | ██║ ██║██║██║ ██║█████╗ ██║ ██║
5 | ╚██╗ ██╔╝██║██║ ██║██╔══╝ ██║ ██║
6 | ╚████╔╝ ██║██████╔╝███████╗╚██████╔╝
7 | ╚═══╝ ╚═╝╚═════╝ ╚══════╝ ╚═════╝
8 | ${AnsiColor.BRIGHT_BLACK}
--------------------------------------------------------------------------------
/video-service/src/test/java/com/zzzi/videoservice/VideoServiceApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.zzzi.videoservice;
2 |
3 | import com.zzzi.common.utils.JwtUtils;
4 | import com.zzzi.videoservice.entity.VideoDO;
5 | import com.zzzi.videoservice.mapper.VideoMapper;
6 | import org.junit.jupiter.api.Test;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
9 | import org.springframework.beans.factory.config.BeanPostProcessor;
10 | import org.springframework.boot.test.context.SpringBootTest;
11 |
12 | import java.text.SimpleDateFormat;
13 | import java.util.Date;
14 |
15 | @SpringBootTest
16 | class VideoServiceApplicationTests {
17 | @Autowired
18 | private VideoMapper videoMapper;
19 |
20 | @Test
21 | void contextLoads() {
22 | }
23 |
24 | @Test
25 | void testParseUserId() {
26 | String token = "eyJhbGciOiJIUzUxMiIsInppcCI6IkdaSVAifQ.H4sIAAAAAAAAAKtWKi5NUrJSconUDQ12DVLSUUqtKFCyMjQ3NDQzMLc0M9BRKi1OLfJMAYmZG1mYmxkYW1haGJuYmpgbGUEk_RJzU4FGGBoaOhQW6iXn5yrVAgBhI68YVwAAAA.tYVj46twIZzN1lJbbeelUqSt50_1zcS1Oujp9NL3WrUKYD7MSgYQE-CqdJiLnM5StVrBm-5dXfLotmyusGUjNg";
27 | Long id = JwtUtils.getUserIdByToken(token);
28 | System.out.println(id);
29 | }
30 |
31 | @Test
32 | void testSubToken() {
33 | String token = "login:token:" + "eyJhbGciOiJIUzUxMiIsInppcCI6IkdaSVAifQ.H4sIAAAAAAAAAKtWKi5NUrJSconUDQ12DVLSUUqtKFCyMjQ3NDQzMLc0M9BRKi1OLfJMAYmZG1mYmxkYW1haGJuYmpgbGUEk_RJzU4FGGBoaOhQW6iXn5yrVAgBhI68YVwAAAA.tYVj46twIZzN1lJbbeelUqSt50_1zcS1Oujp9NL3WrUKYD7MSgYQE-CqdJiLnM5StVrBm-5dXfLotmyusGUjNg";
34 | token = token.substring(12);
35 | System.out.println(token);
36 | }
37 |
38 | @Test
39 | void testParseDate() {
40 | VideoDO videoDO = videoMapper.selectById(1775447822198992898L);
41 | Date createTime = videoDO.getCreateTime();
42 | SimpleDateFormat sdf = new SimpleDateFormat("MM-dd");
43 | String create_date = sdf.format(createTime);
44 | System.out.println(create_date);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------