读书的意义:在浮华的盛世里,享受清灵;找到一个人给自己讲故事,飘到一片新大陆,不同的规则,不同的人与事,感觉,又活了一辈子。
1. 项目介绍及环境配置
2. 短信验证码登录
3. 用户信息
4. MongoDB
5. 推荐好友列表/MongoDB集群/动态发布与查看
6.圈子动态/圈子互动
7. 即时通讯(基于第三方API)
8. 附近的人(百度地图APi)
9. 小视频
10.网关配置
11.后台管理
编辑 tanhua-app-server/src/main/java/com/tanhua/server/controller/MovementController.java
文件:
@RestController
@RequestMapping("/movements")
public class MovementController {
@Autowired
private MovementService movementService;
/**
* 发布动态
* @return
*/
@PostMapping
public ResponseEntity movements(Movement movement, MultipartFile imageContent[]) throws IOException {
movementService.publishMovement(movement, imageContent);
return ResponseEntity.ok(null);
}
/**
* 查询我的动态
*/
@GetMapping("/all")
public ResponseEntity findByUserId(Long userId,
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pagesize) {
PageResult pr = movementService.findByUserId(userId, page, pagesize);
return ResponseEntity.ok(pr);
}
/**
* 查询好友动态
*/
@GetMapping()
public ResponseEntity movements( @RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pagesize) {
PageResult pr = movementService.findFriendMovements(page, pagesize);
return ResponseEntity.ok(pr);
}
}
编辑 tanhua-app-server/src/main/java/com/tanhua/server/service/MovementService.java
文件:
@Service
public class MovementService {
@Autowired
private OssTemplate ossTemplate;
@DubboReference
private MovementApi movementApi;
@DubboReference
private UserInfoApi userInfoApi;
/**
* 发布动态
*/
public void publishMovement(Movement movement, MultipartFile[] imageContent) throws IOException {
// 1. 判断发布动态的内容是否存在
if(StringUtils.isEmpty(movement.getTextContent())) {
throw new BusinessException(ErrorResult.contentError());
}
// 2. 获取当前登录的用户id
Long userId = UserHolder.getUserId();
// 3. 将文件内容上传到阿里云OSS, 获取请求地址
List<String> medias = new ArrayList<>();
for (MultipartFile multipartFile : imageContent) {
// String upload = ossTemplate.upload(multipartFile.getOriginalFilename(), multipartFile.getInputStream());
// !!! 阿里云OSS收费, 这里暂时跳过
String upload = "https://img0.baidu.com/it/u=1501084209,93021381&fm=253&fmt=auto&app=138&f=JPEG";
medias.add(upload);
}
// 4. 将数据封装到movement对象
movement.setUserId(userId);
movement.setMedias(medias);
//5. 调用API完成动态发布
movementApi.publish(movement);
}
// 查询我的动态
public PageResult findByUserId(Long userId, Integer page, Integer pagesize) {
// 1. 根据用户id, 调用API查询个人动态内容(PageResult -- Movement)
PageResult pr = movementApi.findByUserId(userId, page, pagesize);
// 2. 获取PageResult中item列表对象
List<Movement> items = (List<Movement>) pr.getItems();
// 3. 非空判断
if(items == null) {
return pr;
}
// 4. 循环数据列表
UserInfo userInfo = userInfoApi.findById(userId);
List<MovementsVo> vos = new ArrayList<>();
for (Movement item : items) {
// 5. 一个Movement构建一个VO对象
MovementsVo vo = MovementsVo.init(userInfo, item);
vos.add(vo);
}
// 6. 构建返回值
pr.setItems(vos);
return pr;
}
// 查询好友动态
public PageResult findFriendMovements(Integer page, Integer pagesize) {
// 1. 获取当前用户id
Long userId = UserHolder.getUserId();
// 2. 调用API查询当前用户好友发布的动态列表
List<Movement> list = movementApi.findFriendMovements(page, pagesize, userId);
// 3. 判断列表是否为空
// if(list == null || list.isEmpty()) {
if(CollUtil.isEmpty(list)) {
return new PageResult();
}
// 4. 提取动态发布人的id列表
List<Long> userIds = CollUtil.getFieldValues(list, "userId", Long.class);
// 5. 根据用户id列表获取用户详情
Map<Long, UserInfo> map = userInfoApi.findByIds(userIds, null);
// 6. 一个Movement构造一个vo对象
List<MovementsVo> vos = new ArrayList<>();
for (Movement movement : list) {
UserInfo userInfo = map.get(movement.getUserId());
if(userInfo != null) {
MovementsVo vo = MovementsVo.init(userInfo, movement);
vos.add(vo);
}
}
// 7. 构造PageResult并返回
return new PageResult(page, pagesize, 0l, vos);
}
}
编辑 tanhua-dubbo/tanhua-dubbo-interface/src/main/java/com/tanhua/dubbo/api/MovementApi.java
文件:
public interface MovementApi {
// 发布动态
void publish(Movement movement);
// 根据用户id,查询此用户发布的动态数据列表
PageResult findByUserId(Long userId, Integer page, Integer pagesize);
// 根据用户id,查询用户好友发布的动态数据列表
List<Movement> findFriendMovements(Integer page, Integer pagesize, Long userId);
}
编辑 tanhua-dubbo/tanhua-dubbo-mongo/src/main/java/com/tanhua/dubbo/api/MovementApiImpl.java
文件:
@DubboService
public class MovementApiImpl implements MovementApi {
@Autowired
private MongoTemplate mongoTemplate;
@Autowired
private IdWorker idWorker;
@Autowired
private TimeLineService timeLineService;
// 发布动态
public void publish(Movement movement) {
try {
// 1. 保存动态详情
// 1.1 设置PID(同名时序列自增)
movement.setPid(idWorker.getNextId("movement"));
// 1.2 设置时间
movement.setCreated(System.currentTimeMillis());
// 1.3 保存动态
mongoTemplate.save(movement);
// // 2. 查询当前用户的好友数据
// Criteria criteria = Criteria.where("userId").is(movement.getUserId());
// Query query = Query.query(criteria);
// List friends = mongoTemplate.find(query, Friend.class);
//
// // 3. 循环好友数据, 构建时间线数据存入数据库
// for (Friend friend : friends) {
// MovementTimeLine timeLine = new MovementTimeLine();
// timeLine.setMovementId(movement.getId());
// timeLine.setUserId(friend.getUserId());
// timeLine.setFriendId(friend.getFriendId());
// timeLine.setCreated(System.currentTimeMillis());
// mongoTemplate.save(timeLine);
// }
// 异步多线程调用
timeLineService.saveTimeLine(movement.getUserId(), movement.getId());
} catch (Exception e) {
// 忽略事物处理
e.printStackTrace();
}
}
// 根据用户id,查询当前用户发布的动态数据列表
@Override
public PageResult findByUserId(Long userId, Integer page, Integer pagesize) {
Criteria criteria = Criteria.where("userId").is(userId);
Query query = Query.query(criteria).skip((page - 1) * pagesize).limit(pagesize)
.with(Sort.by(Sort.Order.desc("created")));
List<Movement> movements = mongoTemplate.find(query, Movement.class);
return new PageResult(page, pagesize, 0l, movements);
}
/**
* 查询用户好友发布的动态数据列表
* @param friendId 当前操作用户id
* @return
*/
public List<Movement> findFriendMovements(Integer page, Integer pagesize, Long friendId) {
// 1. 根据friendId查询时间线表
Query query = Query.query(Criteria.where("friendId").is(friendId))
.skip((page - 1) * pagesize).limit(pagesize)
.with(Sort.by(Sort.Order.desc("created")));
List<MovementTimeLine> lineList = mongoTemplate.find(query, MovementTimeLine.class);
// 2. 提取动态id列表
List<ObjectId> list = CollUtil.getFieldValues(lineList, "movementId", ObjectId.class);
// 3. 根据动态id查询动态详情
Query movementQuery = Query.query(Criteria.where("id").is(list));
List<Movement> movementList = mongoTemplate.find(movementQuery, Movement.class);
// 4. 返回
return movementList;
}
}
编辑 tanhua-app-server/src/main/java/com/tanhua/server/controller/MovementController.java
文件:
@RestController
@RequestMapping("/movements")
public class MovementController {
@Autowired
private MovementService movementService;
/**
* 发布动态
* @return
*/
@PostMapping
public ResponseEntity movements(Movement movement, MultipartFile imageContent[]) throws IOException {
movementService.publishMovement(movement, imageContent);
return ResponseEntity.ok(null);
}
/**
* 查询我的动态
*/
@GetMapping("/all")
public ResponseEntity findByUserId(Long userId,
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pagesize) {
PageResult pr = movementService.findByUserId(userId, page, pagesize);
return ResponseEntity.ok(pr);
}
/**
* 查询好友动态
*/
@GetMapping()
public ResponseEntity movements( @RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pagesize) {
PageResult pr = movementService.findFriendMovements(page, pagesize);
return ResponseEntity.ok(pr);
}
/**
* 查询推荐动态
*/
@GetMapping("/recommend")
public ResponseEntity recommend( @RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pagesize) {
PageResult pr = movementService.findRecommendMovements(page, pagesize);
return ResponseEntity.ok(pr);
}
}
新建 tanhua-commons/src/main/java/com/tanhua/commons/utils/Constants.java
文件:
//常量定义
public class Constants {
//手机APP短信验证码CHECK_CODE_
public static final String SMS_CODE = "CHECK_CODE_";
//推荐动态
public static final String MOVEMENTS_RECOMMEND = "MOVEMENTS_RECOMMEND_";
//推荐视频
public static final String VIDEOS_RECOMMEND = "VIDEOS_RECOMMEND_";
//圈子互动KEY
public static final String MOVEMENTS_INTERACT_KEY = "MOVEMENTS_INTERACT_";
//动态点赞用户HashKey
public static final String MOVEMENT_LIKE_HASHKEY = "MOVEMENT_LIKE_";
//动态喜欢用户HashKey
public static final String MOVEMENT_LOVE_HASHKEY = "MOVEMENT_LOVE_";
//视频点赞用户HashKey
public static final String VIDEO_LIKE_HASHKEY = "VIDEO_LIKE";
//访问用户
public static final String VISITORS = "VISITORS";
//关注用户
public static final String FOCUS_USER = "FOCUS_USER_{}_{}";
//初始化密码
public static final String INIT_PASSWORD = "123456";
//环信用户前缀
public static final String HX_USER_PREFIX = "hx";
//jwt加密盐
public static final String JWT_SECRET = "itcast";
//jwt超时时间
public static final int JWT_TIME_OUT = 3_600;
}
编辑 tanhua-app-server/src/main/java/com/tanhua/server/service/MovementService.java
文件:
@Service
public class MovementService {
@Autowired
private OssTemplate ossTemplate;
@DubboReference
private MovementApi movementApi;
@DubboReference
private UserInfoApi userInfoApi;
@Autowired
private RedisTemplate<String, String> redisTemplate;
/**
* 发布动态
*/
public void publishMovement(Movement movement, MultipartFile[] imageContent) throws IOException {
// 1. 判断发布动态的内容是否存在
if(StringUtils.isEmpty(movement.getTextContent())) {
throw new BusinessException(ErrorResult.contentError());
}
// 2. 获取当前登录的用户id
Long userId = UserHolder.getUserId();
// 3. 将文件内容上传到阿里云OSS, 获取请求地址
List<String> medias = new ArrayList<>();
for (MultipartFile multipartFile : imageContent) {
// String upload = ossTemplate.upload(multipartFile.getOriginalFilename(), multipartFile.getInputStream());
// !!! 阿里云OSS收费, 这里暂时跳过
String upload = "https://img0.baidu.com/it/u=1501084209,93021381&fm=253&fmt=auto&app=138&f=JPEG";
medias.add(upload);
}
// 4. 将数据封装到movement对象
movement.setUserId(userId);
movement.setMedias(medias);
//5. 调用API完成动态发布
movementApi.publish(movement);
}
// 查询我的动态
public PageResult findByUserId(Long userId, Integer page, Integer pagesize) {
// 1. 根据用户id, 调用API查询个人动态内容(PageResult -- Movement)
PageResult pr = movementApi.findByUserId(userId, page, pagesize);
// 2. 获取PageResult中item列表对象
List<Movement> items = (List<Movement>) pr.getItems();
// 3. 非空判断
if(items == null) {
return pr;
}
// 4. 循环数据列表
UserInfo userInfo = userInfoApi.findById(userId);
List<MovementsVo> vos = new ArrayList<>();
for (Movement item : items) {
// 5. 一个Movement构建一个VO对象
MovementsVo vo = MovementsVo.init(userInfo, item);
vos.add(vo);
}
// 6. 构建返回值
pr.setItems(vos);
return pr;
}
// 查询好友动态
public PageResult findFriendMovements(Integer page, Integer pagesize) {
// 1. 获取当前用户id
Long userId = UserHolder.getUserId();
// 2. 调用API查询当前用户好友发布的动态列表
List<Movement> list = movementApi.findFriendMovements(page, pagesize, userId);
return getPageResult(page, pagesize, list);
}
// 公共方法
private PageResult getPageResult(Integer page, Integer pagesize, List<Movement> list) {
// 3. 判断列表是否为空
// if(list == null || list.isEmpty()) {
if(CollUtil.isEmpty(list)) {
return new PageResult();
}
// 4. 提取动态发布人的id列表
List<Long> userIds = CollUtil.getFieldValues(list, "userId", Long.class);
// 5. 根据用户id列表获取用户详情
Map<Long, UserInfo> map = userInfoApi.findByIds(userIds, null);
// 6. 一个Movement构造一个vo对象
List<MovementsVo> vos = new ArrayList<>();
for (Movement movement : list) {
UserInfo userInfo = map.get(movement.getUserId());
if(userInfo != null) {
MovementsVo vo = MovementsVo.init(userInfo, movement);
vos.add(vo);
}
}
// 7. 构造PageResult并返回
return new PageResult(page, pagesize, 0l, vos);
}
// 查询推荐动态
public PageResult findRecommendMovements(Integer page, Integer pagesize) {
// 1. 从redis从获取推荐数据
String redisKey = Constants.MOVEMENTS_RECOMMEND + UserHolder.getUserId();
String redisValue = redisTemplate.opsForValue().get(redisKey);
// 2. 判断推荐数据是否存在
List<Movement> list = Collections.EMPTY_LIST;
if(StringUtils.isEmpty(redisValue)) {
// 3. 如果不存在, 调用API随机构造10条动态数据
list = movementApi.randomMovements(pagesize);
} else {
// 4. 如果存在, 处理pid数据 "16,17,18,19,20,21,10015,10020,10040,10064,10092,10093,10099,10067"
String[] values = redisValue.split(",");
// 4.1 判断当前页的起始条数是否小于数组的总数
if((page - 1) * pagesize < values.length) {
List<Long> pids = Arrays.stream(values).skip((page - 1) * pagesize).limit(pagesize)
.map(e -> Long.valueOf(e))
.collect(Collectors.toList());
// 5. 调用API根据PID数组查询动态数据
list = movementApi.findMovementByPids(pids);
}
}
// 6. 调用公共方法构造返回值
return getPageResult(page, pagesize, list);
}
}
编辑 tanhua-dubbo/tanhua-dubbo-interface/src/main/java/com/tanhua/dubbo/api/MovementApi.java
文件:
public interface MovementApi {
// 发布动态
void publish(Movement movement);
// 根据用户id,查询此用户发布的动态数据列表
PageResult findByUserId(Long userId, Integer page, Integer pagesize);
// 根据用户id,查询用户好友发布的动态数据列表
List<Movement> findFriendMovements(Integer page, Integer pagesize, Long userId);
// 随机获取多条动态数据
List<Movement> randomMovements(Integer counts);
// 根据pid数组查询动态
List<Movement> findMovementByPids(List<Long> pids);
}
编辑 tanhua-dubbo/tanhua-dubbo-mongo/src/main/java/com/tanhua/dubbo/api/MovementApiImpl.java
文件:
@DubboService
public class MovementApiImpl implements MovementApi {
@Autowired
private MongoTemplate mongoTemplate;
@Autowired
private IdWorker idWorker;
@Autowired
private TimeLineService timeLineService;
// 发布动态
public void publish(Movement movement) {
try {
// 1. 保存动态详情
// 1.1 设置PID(同名时序列自增)
movement.setPid(idWorker.getNextId("movement"));
// 1.2 设置时间
movement.setCreated(System.currentTimeMillis());
// 1.3 保存动态
mongoTemplate.save(movement);
// // 2. 查询当前用户的好友数据
// Criteria criteria = Criteria.where("userId").is(movement.getUserId());
// Query query = Query.query(criteria);
// List friends = mongoTemplate.find(query, Friend.class);
//
// // 3. 循环好友数据, 构建时间线数据存入数据库
// for (Friend friend : friends) {
// MovementTimeLine timeLine = new MovementTimeLine();
// timeLine.setMovementId(movement.getId());
// timeLine.setUserId(friend.getUserId());
// timeLine.setFriendId(friend.getFriendId());
// timeLine.setCreated(System.currentTimeMillis());
// mongoTemplate.save(timeLine);
// }
// 异步多线程调用
timeLineService.saveTimeLine(movement.getUserId(), movement.getId());
} catch (Exception e) {
// 忽略事物处理
e.printStackTrace();
}
}
// 根据用户id,查询当前用户发布的动态数据列表
@Override
public PageResult findByUserId(Long userId, Integer page, Integer pagesize) {
Criteria criteria = Criteria.where("userId").is(userId);
Query query = Query.query(criteria).skip((page - 1) * pagesize).limit(pagesize)
.with(Sort.by(Sort.Order.desc("created")));
List<Movement> movements = mongoTemplate.find(query, Movement.class);
return new PageResult(page, pagesize, 0l, movements);
}
/**
* 查询用户好友发布的动态数据列表
* @param friendId 当前操作用户id
* @return
*/
public List<Movement> findFriendMovements(Integer page, Integer pagesize, Long friendId) {
// 1. 根据friendId查询时间线表
Query query = Query.query(Criteria.where("friendId").is(friendId))
.skip((page - 1) * pagesize).limit(pagesize)
.with(Sort.by(Sort.Order.desc("created")));
List<MovementTimeLine> lineList = mongoTemplate.find(query, MovementTimeLine.class);
// 2. 提取动态id列表
List<ObjectId> list = CollUtil.getFieldValues(lineList, "movementId", ObjectId.class);
// 3. 根据动态id查询动态详情
Query movementQuery = Query.query(Criteria.where("id").is(list));
List<Movement> movementList = mongoTemplate.find(movementQuery, Movement.class);
// 4. 返回
return movementList;
}
// 随机获取多条动态数据
@Override
public List<Movement> randomMovements(Integer counts) {
// 1. 创建统计对象, 设置统计参数
TypedAggregation aggregation = Aggregation.newAggregation(Movement.class, Aggregation.sample(counts));
// 2. 调用mongoTemplate方法进行统计
AggregationResults<Movement> results = mongoTemplate.aggregate(aggregation, Movement.class);
// 3. 获取统计结果
return results.getMappedResults();
}
// 根据pid数组获取动态数据
@Override
public List<Movement> findMovementByPids(List<Long> pids) {
Query query = Query.query(Criteria.where("pid").in(pids));
return mongoTemplate.find(query, Movement.class);
}
}
编辑 tanhua-app-server/src/main/java/com/tanhua/server/controller/MovementController.java
文件:
@RestController
@RequestMapping("/movements")
public class MovementController {
@Autowired
private MovementService movementService;
/**
* 发布动态
* @return
*/
@PostMapping
public ResponseEntity movements(Movement movement, MultipartFile imageContent[]) throws IOException {
movementService.publishMovement(movement, imageContent);
return ResponseEntity.ok(null);
}
/**
* 查询我的动态
*/
@GetMapping("/all")
public ResponseEntity findByUserId(Long userId,
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pagesize) {
PageResult pr = movementService.findByUserId(userId, page, pagesize);
return ResponseEntity.ok(pr);
}
/**
* 查询好友动态
*/
@GetMapping()
public ResponseEntity movements( @RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pagesize) {
PageResult pr = movementService.findFriendMovements(page, pagesize);
return ResponseEntity.ok(pr);
}
/**
* 查询推荐动态
*/
@GetMapping("/recommend")
public ResponseEntity recommend( @RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pagesize) {
PageResult pr = movementService.findRecommendMovements(page, pagesize);
return ResponseEntity.ok(pr);
}
/**
* 查询单条动态
*/
@GetMapping("/{id}")
public ResponseEntity findById(@PathVariable("id") String movementId) {
MovementsVo vo = movementService.findById(movementId);
return ResponseEntity.ok(vo);
}
}
编辑 tanhua-app-server/src/main/java/com/tanhua/server/service/MovementService.java
文件:
@Service
public class MovementService {
@Autowired
private OssTemplate ossTemplate;
@DubboReference
private MovementApi movementApi;
@DubboReference
private UserInfoApi userInfoApi;
@Autowired
private RedisTemplate<String, String> redisTemplate;
/**
* 发布动态
*/
public void publishMovement(Movement movement, MultipartFile[] imageContent) throws IOException {
// 1. 判断发布动态的内容是否存在
if(StringUtils.isEmpty(movement.getTextContent())) {
throw new BusinessException(ErrorResult.contentError());
}
// 2. 获取当前登录的用户id
Long userId = UserHolder.getUserId();
// 3. 将文件内容上传到阿里云OSS, 获取请求地址
List<String> medias = new ArrayList<>();
for (MultipartFile multipartFile : imageContent) {
// String upload = ossTemplate.upload(multipartFile.getOriginalFilename(), multipartFile.getInputStream());
// !!! 阿里云OSS收费, 这里暂时跳过
String upload = "https://img0.baidu.com/it/u=1501084209,93021381&fm=253&fmt=auto&app=138&f=JPEG";
medias.add(upload);
}
// 4. 将数据封装到movement对象
movement.setUserId(userId);
movement.setMedias(medias);
//5. 调用API完成动态发布
movementApi.publish(movement);
}
// 查询我的动态
public PageResult findByUserId(Long userId, Integer page, Integer pagesize) {
// 1. 根据用户id, 调用API查询个人动态内容(PageResult -- Movement)
PageResult pr = movementApi.findByUserId(userId, page, pagesize);
// 2. 获取PageResult中item列表对象
List<Movement> items = (List<Movement>) pr.getItems();
// 3. 非空判断
if(items == null) {
return pr;
}
// 4. 循环数据列表
UserInfo userInfo = userInfoApi.findById(userId);
List<MovementsVo> vos = new ArrayList<>();
for (Movement item : items) {
// 5. 一个Movement构建一个VO对象
MovementsVo vo = MovementsVo.init(userInfo, item);
vos.add(vo);
}
// 6. 构建返回值
pr.setItems(vos);
return pr;
}
// 查询好友动态
public PageResult findFriendMovements(Integer page, Integer pagesize) {
// 1. 获取当前用户id
Long userId = UserHolder.getUserId();
// 2. 调用API查询当前用户好友发布的动态列表
List<Movement> list = movementApi.findFriendMovements(page, pagesize, userId);
return getPageResult(page, pagesize, list);
}
// 公共方法
private PageResult getPageResult(Integer page, Integer pagesize, List<Movement> list) {
// 3. 判断列表是否为空
// if(list == null || list.isEmpty()) {
if(CollUtil.isEmpty(list)) {
return new PageResult();
}
// 4. 提取动态发布人的id列表
List<Long> userIds = CollUtil.getFieldValues(list, "userId", Long.class);
// 5. 根据用户id列表获取用户详情
Map<Long, UserInfo> map = userInfoApi.findByIds(userIds, null);
// 6. 一个Movement构造一个vo对象
List<MovementsVo> vos = new ArrayList<>();
for (Movement movement : list) {
UserInfo userInfo = map.get(movement.getUserId());
if(userInfo != null) {
MovementsVo vo = MovementsVo.init(userInfo, movement);
vos.add(vo);
}
}
// 7. 构造PageResult并返回
return new PageResult(page, pagesize, 0l, vos);
}
// 查询推荐动态
public PageResult findRecommendMovements(Integer page, Integer pagesize) {
// 1. 从redis从获取推荐数据
String redisKey = Constants.MOVEMENTS_RECOMMEND + UserHolder.getUserId();
String redisValue = redisTemplate.opsForValue().get(redisKey);
// 2. 判断推荐数据是否存在
List<Movement> list = Collections.EMPTY_LIST;
if(StringUtils.isEmpty(redisValue)) {
// 3. 如果不存在, 调用API随机构造10条动态数据
list = movementApi.randomMovements(pagesize);
} else {
// 4. 如果存在, 处理pid数据 "16,17,18,19,20,21,10015,10020,10040,10064,10092,10093,10099,10067"
String[] values = redisValue.split(",");
// 4.1 判断当前页的起始条数是否小于数组的总数
if((page - 1) * pagesize < values.length) {
List<Long> pids = Arrays.stream(values).skip((page - 1) * pagesize).limit(pagesize)
.map(e -> Long.valueOf(e))
.collect(Collectors.toList());
// 5. 调用API根据PID数组查询动态数据
list = movementApi.findMovementByPids(pids);
}
}
// 6. 调用公共方法构造返回值
return getPageResult(page, pagesize, list);
}
// 查询单条动态
public MovementsVo findById(String movementId) {
// 1. 调用API查询动态详情
Movement movement = movementApi.findById(movementId);
// 2. 转换vo对象
if(movement != null) {
UserInfo userInfo = userInfoApi.findById(movement.getUserId());
return MovementsVo.init(userInfo, movement);
} else {
return null;
}
}
}
编辑 tanhua-dubbo/tanhua-dubbo-interface/src/main/java/com/tanhua/dubbo/api/MovementApi.java
文件:
public interface MovementApi {
// 发布动态
void publish(Movement movement);
// 根据用户id,查询此用户发布的动态数据列表
PageResult findByUserId(Long userId, Integer page, Integer pagesize);
// 根据用户id,查询用户好友发布的动态数据列表
List<Movement> findFriendMovements(Integer page, Integer pagesize, Long userId);
// 随机获取多条动态数据
List<Movement> randomMovements(Integer counts);
// 根据pid数组查询动态
List<Movement> findMovementByPids(List<Long> pids);
// 查询单条动态
Movement findById(String movementId);
}
编辑 tanhua-dubbo/tanhua-dubbo-mongo/src/main/java/com/tanhua/dubbo/api/MovementApiImpl.java
文件:
@DubboService
public class MovementApiImpl implements MovementApi {
@Autowired
private MongoTemplate mongoTemplate;
@Autowired
private IdWorker idWorker;
@Autowired
private TimeLineService timeLineService;
// 发布动态
public void publish(Movement movement) {
try {
// 1. 保存动态详情
// 1.1 设置PID(同名时序列自增)
movement.setPid(idWorker.getNextId("movement"));
// 1.2 设置时间
movement.setCreated(System.currentTimeMillis());
// 1.3 保存动态
mongoTemplate.save(movement);
// // 2. 查询当前用户的好友数据
// Criteria criteria = Criteria.where("userId").is(movement.getUserId());
// Query query = Query.query(criteria);
// List friends = mongoTemplate.find(query, Friend.class);
//
// // 3. 循环好友数据, 构建时间线数据存入数据库
// for (Friend friend : friends) {
// MovementTimeLine timeLine = new MovementTimeLine();
// timeLine.setMovementId(movement.getId());
// timeLine.setUserId(friend.getUserId());
// timeLine.setFriendId(friend.getFriendId());
// timeLine.setCreated(System.currentTimeMillis());
// mongoTemplate.save(timeLine);
// }
// 异步多线程调用
timeLineService.saveTimeLine(movement.getUserId(), movement.getId());
} catch (Exception e) {
// 忽略事物处理
e.printStackTrace();
}
}
// 根据用户id,查询当前用户发布的动态数据列表
@Override
public PageResult findByUserId(Long userId, Integer page, Integer pagesize) {
Criteria criteria = Criteria.where("userId").is(userId);
Query query = Query.query(criteria).skip((page - 1) * pagesize).limit(pagesize)
.with(Sort.by(Sort.Order.desc("created")));
List<Movement> movements = mongoTemplate.find(query, Movement.class);
return new PageResult(page, pagesize, 0l, movements);
}
/**
* 查询用户好友发布的动态数据列表
* @param friendId 当前操作用户id
* @return
*/
public List<Movement> findFriendMovements(Integer page, Integer pagesize, Long friendId) {
// 1. 根据friendId查询时间线表
Query query = Query.query(Criteria.where("friendId").is(friendId))
.skip((page - 1) * pagesize).limit(pagesize)
.with(Sort.by(Sort.Order.desc("created")));
List<MovementTimeLine> lineList = mongoTemplate.find(query, MovementTimeLine.class);
// 2. 提取动态id列表
List<ObjectId> list = CollUtil.getFieldValues(lineList, "movementId", ObjectId.class);
// 3. 根据动态id查询动态详情
Query movementQuery = Query.query(Criteria.where("id").is(list));
List<Movement> movementList = mongoTemplate.find(movementQuery, Movement.class);
// 4. 返回
return movementList;
}
// 随机获取多条动态数据
@Override
public List<Movement> randomMovements(Integer counts) {
// 1. 创建统计对象, 设置统计参数
TypedAggregation aggregation = Aggregation.newAggregation(Movement.class, Aggregation.sample(counts));
// 2. 调用mongoTemplate方法进行统计
AggregationResults<Movement> results = mongoTemplate.aggregate(aggregation, Movement.class);
// 3. 获取统计结果
return results.getMappedResults();
}
// 根据pid数组获取动态数据
@Override
public List<Movement> findMovementByPids(List<Long> pids) {
Query query = Query.query(Criteria.where("pid").in(pids));
return mongoTemplate.find(query, Movement.class);
}
// 查询单条动态
@Override
public Movement findById(String movementId) {
return mongoTemplate.findById(movementId, Movement.class);
}
}
新建 tanhua-model/src/main/java/com/tanhua/model/mongo/Comment.java
文件:
/**
* 圈子互动表(点赞,评论,喜欢)
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(collection = "comment")
public class Comment implements java.io.Serializable{
private ObjectId id;
private ObjectId publishId; //发布id
private Integer commentType; //评论类型,1-点赞,2-评论,3-喜欢
private String content; //评论内容
private Long userId; //评论人
private Long publishUserId; //被评论人ID
private Long created; //发表时间
private Integer likeCount = 0; //当前评论的点赞数
}
新建 tanhua-model/src/main/java/com/tanhua/model/vo/CommentVo.java
文件:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CommentVo implements Serializable {
private String id; //评论id
private String avatar; //头像
private String nickname; //昵称
private String content; //评论
private String createDate; //评论时间
private Integer likeCount; //点赞数
private Integer hasLiked; //是否点赞(1是,0否)
public static CommentVo init(UserInfo userInfo, Comment item) {
CommentVo vo = new CommentVo();
BeanUtils.copyProperties(userInfo, vo);
BeanUtils.copyProperties(item, vo);
vo.setHasLiked(0);
Date date = new Date(item.getCreated());
vo.setCreateDate(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date));
vo.setId(item.getId().toHexString());
return vo;
}
}
编辑 tanhua-model/src/main/java/com/tanhua/model/mongo/Movement.java
文件:
//动态详情表
@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(collection = "movement")
public class Movement implements java.io.Serializable {
private ObjectId id; //主键id
// redis实现, 或者使用MongoDB实现
private Long pid; //Long类型,用于推荐系统的模型(自动增长)
private Long created; //发布时间
private Long userId;
private String textContent; //文字
private List<String> medias; //媒体数据,图片或小视频 url
private String longitude; //经度
private String latitude; //纬度
private String locationName; //位置名称
private Integer state = 0;//状态 0:未审(默认),1:通过,2:驳回
//补充字段
private Integer likeCount = 0; //点赞数
private Integer commentCount = 0; //评论数
private Integer loveCount = 0; //喜欢数
//根据评论类型,获取对应的互动数量
public Integer statisCount(Integer commentType) {
if (commentType == CommentType.LIKE.getType()) {
return this.likeCount;
} else if (commentType == CommentType.COMMENT.getType()) {
return this.commentCount;
} else {
return loveCount;
}
}
}
新建 tanhua-model/src/main/java/com/tanhua/model/enums/CommentType.java
文件:
/**
* 评论类型:1-点赞,2-评论,3-喜欢
*/
public enum CommentType {
LIKE(1), COMMENT(2), LOVE(3);
int type;
CommentType(int type) {
this.type = type;
}
public int getType() {
return type;
}
}
新建 tanhua-app-server/src/main/java/com/tanhua/server/controller/CommentsController.java
文件:
@RestController
@RequestMapping("/comments")
public class CommentsController {
@Autowired
private CommentsService commentsService;
/**
* 发布评论
*/
@PostMapping
public ResponseEntity saveComments(@RequestBody Map map) {
String movementId = (String) map.get("movementId");
String comment = (String) map.get("comment");
commentsService.saveComments(movementId, comment);
return ResponseEntity.ok(null);
}
}
新建 tanhua-app-server/src/main/java/com/tanhua/server/service/CommentsService.java
文件:
@Service
@Slf4j
public class CommentsService {
@DubboReference
private CommentApi commentApi;
// 发布评论
public void saveComments(String movementId, String comment) {
// 1. 获取操作用户id
Long userId = UserHolder.getUserId();
// 2. 构造Comment
Comment comment1 = new Comment();
comment1.setPublishId(new ObjectId(movementId));
comment1.setCommentType(CommentType.COMMENT.getType());
comment1.setContent(comment);
comment1.setUserId(userId);
comment1.setCreated(System.currentTimeMillis());
// 3. 调用Service保存评论
Integer commentCount = commentApi.save(comment1);
log.info("commentCount =" + commentCount);
}
}
新建 tanhua-dubbo/tanhua-dubbo-interface/src/main/java/com/tanhua/dubbo/api/CommentApi.java
文件:
public interface CommentApi {
// 发布评论, 并获得评论数量
Integer save(Comment comment);
}
新建 tanhua-dubbo/tanhua-dubbo-mongo/src/main/java/com/tanhua/dubbo/api/CommentApiImpl.java
文件:
@DubboService
public class CommentApiImpl implements CommentApi{
@Autowired
private MongoTemplate mongoTemplate;
// 发布评论, 获取评论数量
public Integer save(Comment comment) {
// 1. 查询动态
Movement movement = mongoTemplate.findById(comment.getPublishId(), Movement.class);
// 2. 向Comment对象设置被评论人属性
if(movement != null) {
comment.setPublishUserId(movement.getUserId());
}
// 3. 保存到数据库
mongoTemplate.save(comment);
// 4. 更新动态表中的对应字段
Query query = Query.query(Criteria.where("id").is(comment.getPublishId()));
Update update = new Update();
if(comment.getCommentType() == CommentType.LIKE.getType()) { // 点赞
update.inc("likeCount", 1);
} else if (comment.getCommentType() == CommentType.COMMENT.getType()) { // 评论
update.inc("commentCount", 1);
} else { // 喜欢
update.inc("loveCount", 1);
}
// 设置更新参数
FindAndModifyOptions options = new FindAndModifyOptions();
options.returnNew(true); // 获取更新后的最新数据
Movement modify = mongoTemplate.findAndModify(query, update, options, Movement.class);
// 5. 获取最新的评论数量, 并返回
return modify.statisCount(comment.getCommentType());
}
}
新建 tanhua-app-server/src/test/java/com/tanhua/test/CommentApiTest.java
文件:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = AppServerApplication.class)
public class CommentApiTest {
@DubboReference
private CommentApi commentApi;
@Test
public void testSave() {
Comment comment = new Comment();
comment.setCommentType(CommentType.COMMENT.getType());
comment.setUserId(106l);
comment.setCreated(System.currentTimeMillis());
comment.setContent("测试评论");
comment.setPublishId(new ObjectId("5e82dc3e6401952928c211a3"));
commentApi.save(comment);
}
}
编辑 tanhua-app-server/src/main/java/com/tanhua/server/controller/CommentsController.java
文件:
@RestController
@RequestMapping("/comments")
public class CommentsController {
@Autowired
private CommentsService commentsService;
/**
* 发布评论
*/
@PostMapping
public ResponseEntity saveComments(@RequestBody Map map) {
String movementId = (String) map.get("movementId");
String comment = (String) map.get("comment");
commentsService.saveComments(movementId, comment);
return ResponseEntity.ok(null);
}
/**
* 分页查询评论列表
*/
@GetMapping
public ResponseEntity findComments(@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pagesize,
String movementId) {
PageResult pr = commentsService.findComments(movementId, page, pagesize);
return ResponseEntity.ok(pr);
}
}
编辑 tanhua-app-server/src/main/java/com/tanhua/server/service/CommentsService.java
文件:
@Service
@Slf4j
public class CommentsService {
@DubboReference
private CommentApi commentApi;
@DubboReference
private UserInfoApi userInfoApi;
// 发布评论
public void saveComments(String movementId, String comment) {
// 1. 获取操作用户id
Long userId = UserHolder.getUserId();
// 2. 构造Comment
Comment comment1 = new Comment();
comment1.setPublishId(new ObjectId(movementId));
comment1.setCommentType(CommentType.COMMENT.getType());
comment1.setContent(comment);
comment1.setUserId(userId);
comment1.setCreated(System.currentTimeMillis());
// 3. 调用Service保存评论
Integer commentCount = commentApi.save(comment1);
log.info("commentCount =" + commentCount);
}
// 分页查询评论列表
public PageResult findComments(String movementId, Integer page, Integer pagesize) {
// 1. 调用API查询分页列表
List<Comment> list = commentApi.findComments(movementId, CommentType.COMMENT, page, pagesize);
// 2. 判断list集合是否存在
if(CollUtil.isEmpty(list)) {
return new PageResult();
}
// 3. 提取所有的用户id, 调用UserInfoApi查询用户详情
List<Long> userIds = CollUtil.getFieldValues(list, "userId", Long.class);
Map<Long, UserInfo> map = userInfoApi.findByIds(userIds, null);
// 4. 构造vo对象
List<CommentVo> vos = new ArrayList<>();
for (Comment comment : list) {
UserInfo userInfo = map.get(comment.getUserId());
if(userInfo != null) {
CommentVo vo = CommentVo.init(userInfo, comment);
vos.add(vo);
}
}
// 5. 构造返回值
return new PageResult(page, pagesize, 0l, vos);
}
}
编辑 tanhua-dubbo/tanhua-dubbo-interface/src/main/java/com/tanhua/dubbo/api/CommentApi.java
文件:
public interface CommentApi {
// 发布评论, 并获得评论数量
Integer save(Comment comment);
// 分页查询评论列表
List<Comment> findComments(String movementId, CommentType commentType, Integer page, Integer pagesize);
}
编辑 tanhua-dubbo/tanhua-dubbo-mongo/src/main/java/com/tanhua/dubbo/api/CommentApiImpl.java
文件:
@DubboService
public class CommentApiImpl implements CommentApi{
@Autowired
private MongoTemplate mongoTemplate;
// 发布评论, 获取评论数量
public Integer save(Comment comment) {
// 1. 查询动态
Movement movement = mongoTemplate.findById(comment.getPublishId(), Movement.class);
// 2. 向Comment对象设置被评论人属性
if(movement != null) {
comment.setPublishUserId(movement.getUserId());
}
// 3. 保存到数据库
mongoTemplate.save(comment);
// 4. 更新动态表中的对应字段
Query query = Query.query(Criteria.where("id").is(comment.getPublishId()));
Update update = new Update();
if(comment.getCommentType() == CommentType.LIKE.getType()) { // 点赞
update.inc("likeCount", 1);
} else if (comment.getCommentType() == CommentType.COMMENT.getType()) { // 评论
update.inc("commentCount", 1);
} else { // 喜欢
update.inc("loveCount", 1);
}
// 设置更新参数
FindAndModifyOptions options = new FindAndModifyOptions();
options.returnNew(true); // 获取更新后的最新数据
Movement modify = mongoTemplate.findAndModify(query, update, options, Movement.class);
// 5. 获取最新的评论数量, 并返回
return modify.statisCount(comment.getCommentType());
}
// 分页查询评论列表
public List<Comment> findComments(String movementId, CommentType commentType, Integer page, Integer pagesize) {
// 1. 构造查询条件
Query query = Query.query(Criteria.where("publishId").is(new ObjectId(movementId))
.and("commentType").is(commentType.getType()))
.skip(( page - 1) * pagesize)
.limit(pagesize)
.with(Sort.by(Sort.Order.desc("created")));
// 2. 查询并发挥
return mongoTemplate.find(query, Comment.class);
}
}
编辑 tanhua-app-server/src/main/java/com/tanhua/server/controller/MovementController.java
文件:
@RestController
@RequestMapping("/movements")
public class MovementController {
@Autowired
private MovementService movementService;
@Autowired
private CommentsService commentsService;
/**
* 发布动态
* @return
*/
@PostMapping
public ResponseEntity movements(Movement movement, MultipartFile imageContent[]) throws IOException {
movementService.publishMovement(movement, imageContent);
return ResponseEntity.ok(null);
}
/**
* 查询我的动态
*/
@GetMapping("/all")
public ResponseEntity findByUserId(Long userId,
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pagesize) {
PageResult pr = movementService.findByUserId(userId, page, pagesize);
return ResponseEntity.ok(pr);
}
/**
* 查询好友动态
*/
@GetMapping()
public ResponseEntity movements( @RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pagesize) {
PageResult pr = movementService.findFriendMovements(page, pagesize);
return ResponseEntity.ok(pr);
}
/**
* 查询推荐动态
*/
@GetMapping("/recommend")
public ResponseEntity recommend( @RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pagesize) {
PageResult pr = movementService.findRecommendMovements(page, pagesize);
return ResponseEntity.ok(pr);
}
/**
* 查询单条动态
*/
@GetMapping("/{id}")
public ResponseEntity findById(@PathVariable("id") String movementId) {
MovementsVo vo = movementService.findById(movementId);
return ResponseEntity.ok(vo);
}
/**
* 点赞
*/
@GetMapping("/{id}/like")
public ResponseEntity like(@PathVariable("id") String movementId) {
Integer likeCount = commentsService.likeComment(movementId);
return ResponseEntity.ok(likeCount);
}
}
编辑 tanhua-app-server/src/main/java/com/tanhua/server/service/CommentsService.java
文件:
@Service
@Slf4j
public class CommentsService {
@DubboReference
private CommentApi commentApi;
@DubboReference
private UserInfoApi userInfoApi;
@Autowired
private RedisTemplate redisTemplate;
// 发布评论
public void saveComments(String movementId, String comment) {
// 1. 获取操作用户id
Long userId = UserHolder.getUserId();
// 2. 构造Comment
Comment comment1 = new Comment();
comment1.setPublishId(new ObjectId(movementId));
comment1.setCommentType(CommentType.COMMENT.getType());
comment1.setContent(comment);
comment1.setUserId(userId);
comment1.setCreated(System.currentTimeMillis());
// 3. 调用Service保存评论
Integer commentCount = commentApi.save(comment1);
log.info("commentCount =" + commentCount);
}
// 分页查询评论列表
public PageResult findComments(String movementId, Integer page, Integer pagesize) {
// 1. 调用API查询分页列表
List<Comment> list = commentApi.findComments(movementId, CommentType.COMMENT, page, pagesize);
// 2. 判断list集合是否存在
if(CollUtil.isEmpty(list)) {
return new PageResult();
}
// 3. 提取所有的用户id, 调用UserInfoApi查询用户详情
List<Long> userIds = CollUtil.getFieldValues(list, "userId", Long.class);
Map<Long, UserInfo> map = userInfoApi.findByIds(userIds, null);
// 4. 构造vo对象
List<CommentVo> vos = new ArrayList<>();
for (Comment comment : list) {
UserInfo userInfo = map.get(comment.getUserId());
if(userInfo != null) {
CommentVo vo = CommentVo.init(userInfo, comment);
vos.add(vo);
}
}
// 5. 构造返回值
return new PageResult(page, pagesize, 0l, vos);
}
// 点赞
public Integer likeComment(String movementId) {
// 1. 调用API查询用户是否已点赞
Boolean hasComment = commentApi.hasComment(movementId, UserHolder.getUserId(), CommentType.LIKE);
// 2. 如果已点赞,抛出异常
if(hasComment) {
throw new BusinessException(ErrorResult.likeError());
}
// 3. 调用API保存数据到mogonDB
Comment comment = new Comment();
comment.setPublishId(new ObjectId(movementId));
comment.setCommentType(CommentType.LIKE.getType());
comment.setUserId(UserHolder.getUserId());
comment.setCreated(System.currentTimeMillis());
Integer count = commentApi.save(comment);
// 4. 拼接redis的key, 将用户的点赞状态存入redis
String key = Constants.MOVEMENTS_INTERACT_KEY + movementId;
String hashKey = Constants.MOVEMENT_LIKE_HASHKEY + UserHolder.getUserId();
redisTemplate.opsForHash().put(key, hashKey, "1");
return count;
}
}
编辑 tanhua-dubbo/tanhua-dubbo-interface/src/main/java/com/tanhua/dubbo/api/CommentApi.java
文件:
public interface CommentApi {
// 发布评论, 并获得评论数量
Integer save(Comment comment);
// 分页查询评论列表
List<Comment> findComments(String movementId, CommentType commentType, Integer page, Integer pagesize);
// 判断comment数据是否存在
Boolean hasComment(String movementId, Long userId, CommentType commentType);
}
编辑 tanhua-dubbo/tanhua-dubbo-mongo/src/main/java/com/tanhua/dubbo/api/CommentApiImpl.java
文件:
@DubboService
public class CommentApiImpl implements CommentApi{
@Autowired
private MongoTemplate mongoTemplate;
// 发布评论, 获取评论数量
public Integer save(Comment comment) {
// 1. 查询动态
Movement movement = mongoTemplate.findById(comment.getPublishId(), Movement.class);
// 2. 向Comment对象设置被评论人属性
if(movement != null) {
comment.setPublishUserId(movement.getUserId());
}
// 3. 保存到数据库
mongoTemplate.save(comment);
// 4. 更新动态表中的对应字段
Query query = Query.query(Criteria.where("id").is(comment.getPublishId()));
Update update = new Update();
if(comment.getCommentType() == CommentType.LIKE.getType()) { // 点赞
update.inc("likeCount", 1);
} else if (comment.getCommentType() == CommentType.COMMENT.getType()) { // 评论
update.inc("commentCount", 1);
} else { // 喜欢
update.inc("loveCount", 1);
}
// 设置更新参数
FindAndModifyOptions options = new FindAndModifyOptions();
options.returnNew(true); // 获取更新后的最新数据
Movement modify = mongoTemplate.findAndModify(query, update, options, Movement.class);
// 5. 获取最新的评论数量, 并返回
return modify.statisCount(comment.getCommentType());
}
// 分页查询评论列表
public List<Comment> findComments(String movementId, CommentType commentType, Integer page, Integer pagesize) {
// 1. 构造查询条件
Query query = Query.query(Criteria.where("publishId").is(new ObjectId(movementId))
.and("commentType").is(commentType.getType()))
.skip(( page - 1) * pagesize)
.limit(pagesize)
.with(Sort.by(Sort.Order.desc("created")));
// 2. 查询并发挥
return mongoTemplate.find(query, Comment.class);
}
// 判断comment数据是否存在
public Boolean hasComment(String movementId, Long userId, CommentType commentType) {
Criteria criteria = Criteria.where("userId").is(userId)
.and("publishId").is(new ObjectId(movementId))
.and("commentType").is(commentType.getType());
Query query = Query.query(criteria);
return mongoTemplate.exists(query, Comment.class); // 判断数据是否存在
}
}
编辑 tanhua-app-server/src/main/java/com/tanhua/server/service/MovementService.java
文件:
@Service
public class MovementService {
@Autowired
private OssTemplate ossTemplate;
@DubboReference
private MovementApi movementApi;
@DubboReference
private UserInfoApi userInfoApi;
@Autowired
private RedisTemplate<String, String> redisTemplate;
/**
* 发布动态
*/
public void publishMovement(Movement movement, MultipartFile[] imageContent) throws IOException {
// 1. 判断发布动态的内容是否存在
if(StringUtils.isEmpty(movement.getTextContent())) {
throw new BusinessException(ErrorResult.contentError());
}
// 2. 获取当前登录的用户id
Long userId = UserHolder.getUserId();
// 3. 将文件内容上传到阿里云OSS, 获取请求地址
List<String> medias = new ArrayList<>();
for (MultipartFile multipartFile : imageContent) {
// String upload = ossTemplate.upload(multipartFile.getOriginalFilename(), multipartFile.getInputStream());
// !!! 阿里云OSS收费, 这里暂时跳过
String upload = "https://img0.baidu.com/it/u=1501084209,93021381&fm=253&fmt=auto&app=138&f=JPEG";
medias.add(upload);
}
// 4. 将数据封装到movement对象
movement.setUserId(userId);
movement.setMedias(medias);
//5. 调用API完成动态发布
movementApi.publish(movement);
}
// 查询我的动态
public PageResult findByUserId(Long userId, Integer page, Integer pagesize) {
// 1. 根据用户id, 调用API查询个人动态内容(PageResult -- Movement)
PageResult pr = movementApi.findByUserId(userId, page, pagesize);
// 2. 获取PageResult中item列表对象
List<Movement> items = (List<Movement>) pr.getItems();
// 3. 非空判断
if(items == null) {
return pr;
}
// 4. 循环数据列表
UserInfo userInfo = userInfoApi.findById(userId);
List<MovementsVo> vos = new ArrayList<>();
for (Movement item : items) {
// 5. 一个Movement构建一个VO对象
MovementsVo vo = MovementsVo.init(userInfo, item);
vos.add(vo);
}
// 6. 构建返回值
pr.setItems(vos);
return pr;
}
// 查询好友动态
public PageResult findFriendMovements(Integer page, Integer pagesize) {
// 1. 获取当前用户id
Long userId = UserHolder.getUserId();
// 2. 调用API查询当前用户好友发布的动态列表
List<Movement> list = movementApi.findFriendMovements(page, pagesize, userId);
return getPageResult(page, pagesize, list);
}
// 公共方法
private PageResult getPageResult(Integer page, Integer pagesize, List<Movement> list) {
// 3. 判断列表是否为空
// if(list == null || list.isEmpty()) {
if(CollUtil.isEmpty(list)) {
return new PageResult();
}
// 4. 提取动态发布人的id列表
List<Long> userIds = CollUtil.getFieldValues(list, "userId", Long.class);
// 5. 根据用户id列表获取用户详情
Map<Long, UserInfo> map = userInfoApi.findByIds(userIds, null);
// 6. 一个Movement构造一个vo对象
List<MovementsVo> vos = new ArrayList<>();
for (Movement movement : list) {
UserInfo userInfo = map.get(movement.getUserId());
if(userInfo != null) {
MovementsVo vo = MovementsVo.init(userInfo, movement);
// 添加点赞状态,判断hashKey是否存在
String key = Constants.MOVEMENTS_INTERACT_KEY + movement.getId().toHexString();
String hashKey = Constants.MOVEMENT_LIKE_HASHKEY + UserHolder.getUserId();
if(redisTemplate.opsForHash().hasKey(key, hashKey)) {
vo.setHasLiked(1);
}
vos.add(vo);
}
}
// 7. 构造PageResult并返回
return new PageResult(page, pagesize, 0l, vos);
}
// 查询推荐动态
public PageResult findRecommendMovements(Integer page, Integer pagesize) {
// 1. 从redis从获取推荐数据
String redisKey = Constants.MOVEMENTS_RECOMMEND + UserHolder.getUserId();
String redisValue = redisTemplate.opsForValue().get(redisKey);
// 2. 判断推荐数据是否存在
List<Movement> list = Collections.EMPTY_LIST;
if(StringUtils.isEmpty(redisValue)) {
// 3. 如果不存在, 调用API随机构造10条动态数据
list = movementApi.randomMovements(pagesize);
} else {
// 4. 如果存在, 处理pid数据 "16,17,18,19,20,21,10015,10020,10040,10064,10092,10093,10099,10067"
String[] values = redisValue.split(",");
// 4.1 判断当前页的起始条数是否小于数组的总数
if((page - 1) * pagesize < values.length) {
List<Long> pids = Arrays.stream(values).skip((page - 1) * pagesize).limit(pagesize)
.map(e -> Long.valueOf(e))
.collect(Collectors.toList());
// 5. 调用API根据PID数组查询动态数据
list = movementApi.findMovementByPids(pids);
}
}
// 6. 调用公共方法构造返回值
return getPageResult(page, pagesize, list);
}
// 查询单条动态
public MovementsVo findById(String movementId) {
// 1. 调用API查询动态详情
Movement movement = movementApi.findById(movementId);
// 2. 转换vo对象
if(movement != null) {
UserInfo userInfo = userInfoApi.findById(movement.getUserId());
return MovementsVo.init(userInfo, movement);
} else {
return null;
}
}
}
编辑 tanhua-app-server/src/main/java/com/tanhua/server/controller/MovementController.java
文件:
@RestController
@RequestMapping("/movements")
public class MovementController {
@Autowired
private MovementService movementService;
@Autowired
private CommentsService commentsService;
/**
* 发布动态
* @return
*/
@PostMapping
public ResponseEntity movements(Movement movement, MultipartFile imageContent[]) throws IOException {
movementService.publishMovement(movement, imageContent);
return ResponseEntity.ok(null);
}
/**
* 查询我的动态
*/
@GetMapping("/all")
public ResponseEntity findByUserId(Long userId,
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pagesize) {
PageResult pr = movementService.findByUserId(userId, page, pagesize);
return ResponseEntity.ok(pr);
}
/**
* 查询好友动态
*/
@GetMapping()
public ResponseEntity movements( @RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pagesize) {
PageResult pr = movementService.findFriendMovements(page, pagesize);
return ResponseEntity.ok(pr);
}
/**
* 查询推荐动态
*/
@GetMapping("/recommend")
public ResponseEntity recommend( @RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pagesize) {
PageResult pr = movementService.findRecommendMovements(page, pagesize);
return ResponseEntity.ok(pr);
}
/**
* 查询单条动态
*/
@GetMapping("/{id}")
public ResponseEntity findById(@PathVariable("id") String movementId) {
MovementsVo vo = movementService.findById(movementId);
return ResponseEntity.ok(vo);
}
/**
* 点赞
*/
@GetMapping("/{id}/like")
public ResponseEntity like(@PathVariable("id") String movementId) {
Integer likeCount = commentsService.likeComment(movementId);
return ResponseEntity.ok(likeCount);
}
/**
* 取消点赞
*/
@GetMapping("/{id}/dislike")
public ResponseEntity dislike(@PathVariable("id") String movementId) {
Integer likeCount = commentsService.dislikeComment(movementId);
return ResponseEntity.ok(likeCount);
}
}
编辑 tanhua-app-server/src/main/java/com/tanhua/server/service/CommentsService.java
文件:
@Service
@Slf4j
public class CommentsService {
@DubboReference
private CommentApi commentApi;
@DubboReference
private UserInfoApi userInfoApi;
@Autowired
private RedisTemplate redisTemplate;
// 发布评论
public void saveComments(String movementId, String comment) {
// 1. 获取操作用户id
Long userId = UserHolder.getUserId();
// 2. 构造Comment
Comment comment1 = new Comment();
comment1.setPublishId(new ObjectId(movementId));
comment1.setCommentType(CommentType.COMMENT.getType());
comment1.setContent(comment);
comment1.setUserId(userId);
comment1.setCreated(System.currentTimeMillis());
// 3. 调用Service保存评论
Integer commentCount = commentApi.save(comment1);
log.info("commentCount =" + commentCount);
}
// 分页查询评论列表
public PageResult findComments(String movementId, Integer page, Integer pagesize) {
// 1. 调用API查询分页列表
List<Comment> list = commentApi.findComments(movementId, CommentType.COMMENT, page, pagesize);
// 2. 判断list集合是否存在
if(CollUtil.isEmpty(list)) {
return new PageResult();
}
// 3. 提取所有的用户id, 调用UserInfoApi查询用户详情
List<Long> userIds = CollUtil.getFieldValues(list, "userId", Long.class);
Map<Long, UserInfo> map = userInfoApi.findByIds(userIds, null);
// 4. 构造vo对象
List<CommentVo> vos = new ArrayList<>();
for (Comment comment : list) {
UserInfo userInfo = map.get(comment.getUserId());
if(userInfo != null) {
CommentVo vo = CommentVo.init(userInfo, comment);
vos.add(vo);
}
}
// 5. 构造返回值
return new PageResult(page, pagesize, 0l, vos);
}
// 点赞
public Integer likeComment(String movementId) {
// 1. 调用API查询用户是否已点赞
Boolean hasComment = commentApi.hasComment(movementId, UserHolder.getUserId(), CommentType.LIKE);
// 2. 如果已点赞,抛出异常
if(hasComment) {
throw new BusinessException(ErrorResult.likeError());
}
// 3. 调用API保存数据到mogonDB
Comment comment = new Comment();
comment.setPublishId(new ObjectId(movementId));
comment.setCommentType(CommentType.LIKE.getType());
comment.setUserId(UserHolder.getUserId());
comment.setCreated(System.currentTimeMillis());
Integer count = commentApi.save(comment);
// 4. 拼接redis的key, 将用户的点赞状态存入redis
String key = Constants.MOVEMENTS_INTERACT_KEY + movementId;
String hashKey = Constants.MOVEMENT_LIKE_HASHKEY + UserHolder.getUserId();
redisTemplate.opsForHash().put(key, hashKey, "1");
// 5. 返回点赞数量
return count;
}
// 取消点赞
public Integer dislikeComment(String movementId) {
// 1. 调用API查询用户是否已点赞
Boolean hasComment = commentApi.hasComment(movementId, UserHolder.getUserId(), CommentType.LIKE);
// 2. 如果未点赞,抛出异常
if(!hasComment) {
throw new BusinessException(ErrorResult.disLikeError());
}
// 3. 调用APi删除数据
Comment comment = new Comment();
comment.setPublishId(new ObjectId(movementId));
comment.setCommentType(CommentType.LIKE.getType());
comment.setUserId(UserHolder.getUserId());
Integer count = commentApi.delete(comment);
// 4. 拼接redis的key, 删除点赞状态
String key = Constants.MOVEMENTS_INTERACT_KEY + movementId;
String hashKey = Constants.MOVEMENT_LIKE_HASHKEY + UserHolder.getUserId();
redisTemplate.opsForHash().delete(key, hashKey);
// 5. 返回点赞数量
return count;
}
}
编辑 tanhua-dubbo/tanhua-dubbo-interface/src/main/java/com/tanhua/dubbo/api/CommentApi.java
文件:
public interface CommentApi {
// 发布评论, 并获得评论数量
Integer save(Comment comment);
// 分页查询评论列表
List<Comment> findComments(String movementId, CommentType commentType, Integer page, Integer pagesize);
// 判断comment数据是否存在
Boolean hasComment(String movementId, Long userId, CommentType commentType);
// 删除comment数据
Integer delete(Comment comment);
}
编辑 tanhua-dubbo/tanhua-dubbo-mongo/src/main/java/com/tanhua/dubbo/api/CommentApiImpl.java
文件:
@DubboService
public class CommentApiImpl implements CommentApi{
@Autowired
private MongoTemplate mongoTemplate;
// 发布评论, 获取评论数量
public Integer save(Comment comment) {
// 1. 查询动态
Movement movement = mongoTemplate.findById(comment.getPublishId(), Movement.class);
// 2. 向Comment对象设置被评论人属性
if(movement != null) {
comment.setPublishUserId(movement.getUserId());
}
// 3. 保存到数据库
mongoTemplate.save(comment);
// 4. 更新动态表中的对应字段
Query query = Query.query(Criteria.where("id").is(comment.getPublishId()));
Update update = new Update();
if(comment.getCommentType() == CommentType.LIKE.getType()) { // 点赞
update.inc("likeCount", 1);
} else if (comment.getCommentType() == CommentType.COMMENT.getType()) { // 评论
update.inc("commentCount", 1);
} else { // 喜欢
update.inc("loveCount", 1);
}
// 设置更新参数
FindAndModifyOptions options = new FindAndModifyOptions();
options.returnNew(true); // 获取更新后的最新数据
Movement modify = mongoTemplate.findAndModify(query, update, options, Movement.class);
// 5. 获取最新的评论数量, 并返回
return modify.statisCount(comment.getCommentType());
}
// 分页查询评论列表
public List<Comment> findComments(String movementId, CommentType commentType, Integer page, Integer pagesize) {
// 1. 构造查询条件
Query query = Query.query(Criteria.where("publishId").is(new ObjectId(movementId))
.and("commentType").is(commentType.getType()))
.skip(( page - 1) * pagesize)
.limit(pagesize)
.with(Sort.by(Sort.Order.desc("created")));
// 2. 查询并发挥
return mongoTemplate.find(query, Comment.class);
}
// 判断comment数据是否存在
public Boolean hasComment(String movementId, Long userId, CommentType commentType) {
Criteria criteria = Criteria.where("userId").is(userId)
.and("publishId").is(new ObjectId(movementId))
.and("commentType").is(commentType.getType());
Query query = Query.query(criteria);
return mongoTemplate.exists(query, Comment.class); // 判断数据是否存在
}
// 删除comment数据
public Integer delete(Comment comment) {
// 1. 删除comment表数据
Criteria criteria = Criteria.where("userId").is(comment.getUserId())
.and("publishId").is(comment.getPublishId())
.and("commentType").is(comment.getCommentType());
Query query = Query.query(criteria);
mongoTemplate.remove(query, Comment.class);
// 2. 修改动态表中的总数量
Query movementQuery = Query.query(Criteria.where("id").is(comment.getPublishId()));
Update update = new Update();
if(comment.getCommentType() == CommentType.LIKE.getType()) { // 点赞
update.inc("likeCount", -1);
} else if (comment.getCommentType() == CommentType.COMMENT.getType()) { // 评论
update.inc("commentCount", -1);
} else { // 喜欢
update.inc("loveCount", -1);
}
// 3. 设置更新参数
FindAndModifyOptions options = new FindAndModifyOptions();
options.returnNew(true); // 获取更新后的最新数据
Movement modify = mongoTemplate.findAndModify(movementQuery, update, options, Movement.class);
// 4. 获取最新的评论数量, 并返回
return modify.statisCount(comment.getCommentType());
}
}
编辑 tanhua-app-server/src/main/java/com/tanhua/server/controller/MovementController.java
文件:
@RestController
@RequestMapping("/movements")
public class MovementController {
@Autowired
private MovementService movementService;
@Autowired
private CommentsService commentsService;
/**
* 发布动态
* @return
*/
@PostMapping
public ResponseEntity movements(Movement movement, MultipartFile imageContent[]) throws IOException {
movementService.publishMovement(movement, imageContent);
return ResponseEntity.ok(null);
}
/**
* 查询我的动态
*/
@GetMapping("/all")
public ResponseEntity findByUserId(Long userId,
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pagesize) {
PageResult pr = movementService.findByUserId(userId, page, pagesize);
return ResponseEntity.ok(pr);
}
/**
* 查询好友动态
*/
@GetMapping()
public ResponseEntity movements( @RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pagesize) {
PageResult pr = movementService.findFriendMovements(page, pagesize);
return ResponseEntity.ok(pr);
}
/**
* 查询推荐动态
*/
@GetMapping("/recommend")
public ResponseEntity recommend( @RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pagesize) {
PageResult pr = movementService.findRecommendMovements(page, pagesize);
return ResponseEntity.ok(pr);
}
/**
* 查询单条动态
*/
@GetMapping("/{id}")
public ResponseEntity findById(@PathVariable("id") String movementId) {
MovementsVo vo = movementService.findById(movementId);
return ResponseEntity.ok(vo);
}
/**
* 点赞
*/
@GetMapping("/{id}/like")
public ResponseEntity like(@PathVariable("id") String movementId) {
Integer likeCount = commentsService.likeComment(movementId);
return ResponseEntity.ok(likeCount);
}
/**
* 取消点赞
*/
@GetMapping("/{id}/dislike")
public ResponseEntity dislike(@PathVariable("id") String movementId) {
Integer likeCount = commentsService.dislikeComment(movementId);
return ResponseEntity.ok(likeCount);
}
/**
* 喜欢
*/
@GetMapping("/{id}/love")
public ResponseEntity love(@PathVariable("id") String movementId) {
Integer likeCount = commentsService.loveComment(movementId);
return ResponseEntity.ok(likeCount);
}
/**
* 取消喜欢
*/
@GetMapping("/{id}/unlove")
public ResponseEntity unlove(@PathVariable("id") String movementId) {
Integer likeCount = commentsService.disloveComment(movementId);
return ResponseEntity.ok(likeCount);
}
}
编辑 tanhua-app-server/src/main/java/com/tanhua/server/service/CommentsService.java
文件:
@Service
@Slf4j
public class CommentsService {
@DubboReference
private CommentApi commentApi;
@DubboReference
private UserInfoApi userInfoApi;
@Autowired
private RedisTemplate redisTemplate;
// 发布评论
public void saveComments(String movementId, String comment) {
// 1. 获取操作用户id
Long userId = UserHolder.getUserId();
// 2. 构造Comment
Comment comment1 = new Comment();
comment1.setPublishId(new ObjectId(movementId));
comment1.setCommentType(CommentType.COMMENT.getType());
comment1.setContent(comment);
comment1.setUserId(userId);
comment1.setCreated(System.currentTimeMillis());
// 3. 调用Service保存评论
Integer commentCount = commentApi.save(comment1);
log.info("commentCount =" + commentCount);
}
// 分页查询评论列表
public PageResult findComments(String movementId, Integer page, Integer pagesize) {
// 1. 调用API查询分页列表
List<Comment> list = commentApi.findComments(movementId, CommentType.COMMENT, page, pagesize);
// 2. 判断list集合是否存在
if(CollUtil.isEmpty(list)) {
return new PageResult();
}
// 3. 提取所有的用户id, 调用UserInfoApi查询用户详情
List<Long> userIds = CollUtil.getFieldValues(list, "userId", Long.class);
Map<Long, UserInfo> map = userInfoApi.findByIds(userIds, null);
// 4. 构造vo对象
List<CommentVo> vos = new ArrayList<>();
for (Comment comment : list) {
UserInfo userInfo = map.get(comment.getUserId());
if(userInfo != null) {
CommentVo vo = CommentVo.init(userInfo, comment);
vos.add(vo);
}
}
// 5. 构造返回值
return new PageResult(page, pagesize, 0l, vos);
}
// 点赞
public Integer likeComment(String movementId) {
// 1. 调用API查询用户是否已点赞
Boolean hasComment = commentApi.hasComment(movementId, UserHolder.getUserId(), CommentType.LIKE);
// 2. 如果已点赞,抛出异常
if(hasComment) {
throw new BusinessException(ErrorResult.likeError());
}
// 3. 调用API保存数据到mogonDB
Comment comment = new Comment();
comment.setPublishId(new ObjectId(movementId));
comment.setCommentType(CommentType.LIKE.getType());
comment.setUserId(UserHolder.getUserId());
comment.setCreated(System.currentTimeMillis());
Integer count = commentApi.save(comment);
// 4. 拼接redis的key, 将用户的点赞状态存入redis
String key = Constants.MOVEMENTS_INTERACT_KEY + movementId;
String hashKey = Constants.MOVEMENT_LIKE_HASHKEY + UserHolder.getUserId();
redisTemplate.opsForHash().put(key, hashKey, "1");
// 5. 返回点赞数量
return count;
}
// 取消点赞
public Integer dislikeComment(String movementId) {
// 1. 调用API查询用户是否已点赞
Boolean hasComment = commentApi.hasComment(movementId, UserHolder.getUserId(), CommentType.LIKE);
// 2. 如果未点赞,抛出异常
if(!hasComment) {
throw new BusinessException(ErrorResult.disLikeError());
}
// 3. 调用APi删除数据
Comment comment = new Comment();
comment.setPublishId(new ObjectId(movementId));
comment.setCommentType(CommentType.LIKE.getType());
comment.setUserId(UserHolder.getUserId());
Integer count = commentApi.delete(comment);
// 4. 拼接redis的key, 删除点赞状态
String key = Constants.MOVEMENTS_INTERACT_KEY + movementId;
String hashKey = Constants.MOVEMENT_LIKE_HASHKEY + UserHolder.getUserId();
redisTemplate.opsForHash().delete(key, hashKey);
// 5. 返回点赞数量
return count;
}
// 喜欢
public Integer loveComment(String movementId) {
// 1. 调用API查询用户是否已喜欢
Boolean hasComment = commentApi.hasComment(movementId, UserHolder.getUserId(), CommentType.LOVE);
// 2. 如果已喜欢,抛出异常
if(hasComment) {
throw new BusinessException(ErrorResult.loveError());
}
// 3. 调用API保存数据到mogonDB
Comment comment = new Comment();
comment.setPublishId(new ObjectId(movementId));
comment.setCommentType(CommentType.LOVE.getType());
comment.setUserId(UserHolder.getUserId());
comment.setCreated(System.currentTimeMillis());
Integer count = commentApi.save(comment);
// 4. 拼接redis的key, 将用户的喜欢状态存入redis
String key = Constants.MOVEMENTS_INTERACT_KEY + movementId;
String hashKey = Constants.MOVEMENT_LOVE_HASHKEY + UserHolder.getUserId();
redisTemplate.opsForHash().put(key, hashKey, "1");
// 5. 返回喜欢数量
return count;
}
// 取消喜欢
public Integer disloveComment(String movementId) {
// 1. 调用API查询用户是否已点赞
Boolean hasComment = commentApi.hasComment(movementId, UserHolder.getUserId(), CommentType.LOVE);
// 2. 如果未点赞,抛出异常
if(!hasComment) {
throw new BusinessException(ErrorResult.disloveError());
}
// 3. 调用APi删除数据
Comment comment = new Comment();
comment.setPublishId(new ObjectId(movementId));
comment.setCommentType(CommentType.LOVE.getType());
comment.setUserId(UserHolder.getUserId());
Integer count = commentApi.delete(comment);
// 4. 拼接redis的key, 删除点赞状态
String key = Constants.MOVEMENTS_INTERACT_KEY + movementId;
String hashKey = Constants.MOVEMENT_LOVE_HASHKEY + UserHolder.getUserId();
redisTemplate.opsForHash().delete(key, hashKey);
// 5. 返回点赞数量
return count;
}
}
编辑 tanhua-app-server/src/main/java/com/tanhua/server/service/MovementService.java
文件:
@Service
public class MovementService {
@Autowired
private OssTemplate ossTemplate;
@DubboReference
private MovementApi movementApi;
@DubboReference
private UserInfoApi userInfoApi;
@Autowired
private RedisTemplate<String, String> redisTemplate;
/**
* 发布动态
*/
public void publishMovement(Movement movement, MultipartFile[] imageContent) throws IOException {
// 1. 判断发布动态的内容是否存在
if(StringUtils.isEmpty(movement.getTextContent())) {
throw new BusinessException(ErrorResult.contentError());
}
// 2. 获取当前登录的用户id
Long userId = UserHolder.getUserId();
// 3. 将文件内容上传到阿里云OSS, 获取请求地址
List<String> medias = new ArrayList<>();
for (MultipartFile multipartFile : imageContent) {
// String upload = ossTemplate.upload(multipartFile.getOriginalFilename(), multipartFile.getInputStream());
// !!! 阿里云OSS收费, 这里暂时跳过
String upload = "https://img0.baidu.com/it/u=1501084209,93021381&fm=253&fmt=auto&app=138&f=JPEG";
medias.add(upload);
}
// 4. 将数据封装到movement对象
movement.setUserId(userId);
movement.setMedias(medias);
//5. 调用API完成动态发布
movementApi.publish(movement);
}
// 查询我的动态
public PageResult findByUserId(Long userId, Integer page, Integer pagesize) {
// 1. 根据用户id, 调用API查询个人动态内容(PageResult -- Movement)
PageResult pr = movementApi.findByUserId(userId, page, pagesize);
// 2. 获取PageResult中item列表对象
List<Movement> items = (List<Movement>) pr.getItems();
// 3. 非空判断
if(items == null) {
return pr;
}
// 4. 循环数据列表
UserInfo userInfo = userInfoApi.findById(userId);
List<MovementsVo> vos = new ArrayList<>();
for (Movement item : items) {
// 5. 一个Movement构建一个VO对象
MovementsVo vo = MovementsVo.init(userInfo, item);
vos.add(vo);
}
// 6. 构建返回值
pr.setItems(vos);
return pr;
}
// 查询好友动态
public PageResult findFriendMovements(Integer page, Integer pagesize) {
// 1. 获取当前用户id
Long userId = UserHolder.getUserId();
// 2. 调用API查询当前用户好友发布的动态列表
List<Movement> list = movementApi.findFriendMovements(page, pagesize, userId);
return getPageResult(page, pagesize, list);
}
// 公共方法
private PageResult getPageResult(Integer page, Integer pagesize, List<Movement> list) {
// 3. 判断列表是否为空
// if(list == null || list.isEmpty()) {
if(CollUtil.isEmpty(list)) {
return new PageResult();
}
// 4. 提取动态发布人的id列表
List<Long> userIds = CollUtil.getFieldValues(list, "userId", Long.class);
// 5. 根据用户id列表获取用户详情
Map<Long, UserInfo> map = userInfoApi.findByIds(userIds, null);
// 6. 一个Movement构造一个vo对象
List<MovementsVo> vos = new ArrayList<>();
for (Movement movement : list) {
UserInfo userInfo = map.get(movement.getUserId());
if(userInfo != null) {
MovementsVo vo = MovementsVo.init(userInfo, movement);
// 添加点赞状态,判断hashKey是否存在
String key = Constants.MOVEMENTS_INTERACT_KEY + movement.getId().toHexString();
String hashKey = Constants.MOVEMENT_LIKE_HASHKEY + UserHolder.getUserId();
if(redisTemplate.opsForHash().hasKey(key, hashKey)) {
vo.setHasLiked(1);
}
// 添加喜欢状态,判断hashKey是否存在
String loveHashKey = Constants.MOVEMENT_LOVE_HASHKEY + UserHolder.getUserId();
if(redisTemplate.opsForHash().hasKey(key, loveHashKey)) {
vo.setHasLoved(1);
}
vos.add(vo);
}
}
// 7. 构造PageResult并返回
return new PageResult(page, pagesize, 0l, vos);
}
// 查询推荐动态
public PageResult findRecommendMovements(Integer page, Integer pagesize) {
// 1. 从redis从获取推荐数据
String redisKey = Constants.MOVEMENTS_RECOMMEND + UserHolder.getUserId();
String redisValue = redisTemplate.opsForValue().get(redisKey);
// 2. 判断推荐数据是否存在
List<Movement> list = Collections.EMPTY_LIST;
if(StringUtils.isEmpty(redisValue)) {
// 3. 如果不存在, 调用API随机构造10条动态数据
list = movementApi.randomMovements(pagesize);
} else {
// 4. 如果存在, 处理pid数据 "16,17,18,19,20,21,10015,10020,10040,10064,10092,10093,10099,10067"
String[] values = redisValue.split(",");
// 4.1 判断当前页的起始条数是否小于数组的总数
if((page - 1) * pagesize < values.length) {
List<Long> pids = Arrays.stream(values).skip((page - 1) * pagesize).limit(pagesize)
.map(e -> Long.valueOf(e))
.collect(Collectors.toList());
// 5. 调用API根据PID数组查询动态数据
list = movementApi.findMovementByPids(pids);
}
}
// 6. 调用公共方法构造返回值
return getPageResult(page, pagesize, list);
}
// 查询单条动态
public MovementsVo findById(String movementId) {
// 1. 调用API查询动态详情
Movement movement = movementApi.findById(movementId);
// 2. 转换vo对象
if(movement != null) {
UserInfo userInfo = userInfoApi.findById(movement.getUserId());
return MovementsVo.init(userInfo, movement);
} else {
return null;
}
}
}