目录
注意:
-
所有的行为数据,都存储到redis中
-
点赞、阅读、不喜欢需要专门创建一个微服务来处理数据,新建模块:heima-leadnews-behavior
-
关注需要在heima-leadnews-user微服务中实现
-
收藏与文章详情数据回显在heima-leadnews-article微服务中实现
1.前置准备
在这部分内容中,因为前后端id精度不一致,导致精度丢失,使数据不准确的问题。
解决思路:在数据传输时以String类型进行传输,后端在接收时转为对应数据类型,即可解决精度丢失问题。
步骤:
- 将day09资料中提供的压缩包,放至common模块的common包下并解压,这样就好了吗?显然不行呀,springboot可不会加载哦,需要在spring.factories文件中将其添加进去,如下
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.heima.common.exception.ExceptionCatch,\
com.heima.common.swagger.SwaggerConfiguration,\
com.heima.common.swagger.Swagger2Configuration,\
com.heima.common.aliyun.GreenTextScan,\
com.heima.common.aliyun.GreenImageScan,\
com.heima.common.tess4j.Tess4jClient,\
com.heima.common.redis.CacheService, \
com.heima.common.jackson.InitJacksonConfig
- 自定义注解,在model模块下的common包中创建annotation包,将下面内容放在其中
package com.heima.model.common.annotation;
import com.fasterxml.jackson.annotation.JacksonAnnotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@JacksonAnnotation
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
pu
另外,还有一个网络问题,这个需要根据自己的ip改一下minio中的index.js文件,修改的话直接使用minio网站的图形化操作就行,具体配置可以去看day09中的对应视频,老师有讲解的。
跨域问题老师在配置中已经提前解决过了,就不需要管了。
2.关注与取消关注
这部分写在user模块中
2.1实体类与mvc拦截器
UserRelationDto:
package com.heima.model.user.dtos;
import com.heima.model.common.annotation.IdEncrypt;
import lombok.Data;
/**
* @author Z-熙玉
* @version 1.0
*/
@Data
public class UserRelationDto {
/*
* 文章id
*/
@IdEncrypt
private Long article;
/*
* 作者id
*/
@IdEncrypt
private Integer authorId;
/*
* 0:关注 1:取消
*/
private Short operation;
}
拦截器在其它模块直接拷贝过来即可(对应config和interceptor包下的内容)
2.2controller
UserRelationController:
package com.heima.user.controller.v1;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.user.dtos.UserRelationDto;
import com.heima.user.service.UserRelationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author Z-熙玉
* @version 1.0
*/
@RestController
@RequestMapping("/api/v1/user")
public class UserRelationController {
@Autowired
private UserRelationService userRelationService;
@PostMapping("/user_follow")
public ResponseResult follow(@RequestBody UserRelationDto dto) {
return userRelationService.follow(dto);
}
}
2.3service实现类
UserRelationServiceImpl:
package com.heima.user.service.impl;
import com.heima.common.constants.BehaviorConstants;
import com.heima.common.redis.CacheService;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.user.dtos.UserRelationDto;
import com.heima.model.user.pojos.ApUser;
import com.heima.user.service.UserRelationService;
import com.heima.utils.thread.AppThreadLocalUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
/**
* @author Z-熙玉
* @version 1.0
*/
@Service
public class UserRelationServiceImpl implements UserRelationService {
@Autowired
private CacheService cacheService;
/**
* 用户关注和取消
* @param dto
* @return
*/
@Override
public ResponseResult follow(UserRelationDto dto) {
//1 参数校验
if (dto.getOperation() == null || dto.getOperation() < 0 || dto.getOperation() > 1) {
return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
}
//2 判断是否登录
ApUser user = AppThreadLocalUtil.getUser();
if (user == null) {
return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
}
Integer apUserId = user.getId();
//3 关注 apuser:follow: apuser:fans:
Integer followUserId = dto.getAuthorId();
if (dto.getOperation() == 0) {
//将对方写入我的关注中
cacheService.zAdd(BehaviorConstants.APUSER_FOLLOW_RELATION + apUserId, followUserId.toString(), System.currentTimeMillis());
//将我写入对方的粉丝中
cacheService.zAdd(BehaviorConstants.APUSER_FANS_RELATION + followUserId, apUserId.toString(), System.currentTimeMillis());
} else {
//取消关注
cacheService.zRemove(BehaviorConstants.APUSER_FANS_RELATION + apUserId, followUserId.toString());
cacheService.zRemove(BehaviorConstants.APUSER_FANS_RELATION + followUserId, apUserId.toString());
}
return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
}
}
3.点赞与取消点赞
3.1实体类与mvc拦截器
LikesBehaviorDto:
package com.heima.model.behavior.dtos;
import lombok.Data;
@Data
public class LikesBehaviorDto {
// 文章、动态、评论等ID
Long articleId;
/**
* 喜欢内容类型
* 0文章
* 1动态
* 2评论
*/
Short type;
/**
* 喜欢操作方式
* 0 点赞
* 1 取消点赞
*/
Short operation;
}
拦截器直接拷贝
3.2controller
AppLikesBehaviorController:
package com.heima.behavior.controller.v1;
import com.heima.behavior.service.AppLikesBehaviorService;
import com.heima.model.behavior.dtos.LikesBehaviorDto;
import com.heima.model.common.dtos.ResponseResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author Z-熙玉
* @version 1.0
*/
@RestController
@RequestMapping("/api/v1/likes_behavior")
public class AppLikesBehaviorController {
@Autowired
private AppLikesBehaviorService appLikesBehaviorService;
@PostMapping
public ResponseResult like(@RequestBody LikesBehaviorDto dto) {
return appLikesBehaviorService.like(dto);
}
}
3.3service实现类
AppLikesBehaviorServiceImpl:
package com.heima.behavior.service.impl;
import com.alibaba.fastjson.JSON;
import com.heima.behavior.service.AppLikesBehaviorService;
import com.heima.common.constants.BehaviorConstants;
import com.heima.common.redis.CacheService;
import com.heima.model.behavior.dtos.LikesBehaviorDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.user.pojos.ApUser;
import com.heima.utils.thread.AppThreadLocalUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* @author Z-熙玉
* @version 1.0
*/
@Service
@Transactional
@Slf4j
public class AppLikesBehaviorServiceImpl implements AppLikesBehaviorService {
@Autowired
private CacheService cacheService;
/**
* 点赞
* @param dto
*/
@Override
public ResponseResult like(LikesBehaviorDto dto) {
//检查参数
if (dto == null || dto.getArticleId() == null || checkParam(dto)) {
return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
}
//是否登录
ApUser user = AppThreadLocalUtil.getUser();
if (user == null) {
return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
}
//点赞 保存数据
if (dto.getOperation() == 0) {
Object obj = cacheService.hGet(BehaviorConstants.LIKE_BEHAVIOR + dto.getArticleId().toString(), user.getId().toString());
if (obj != null) {
return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID,"已点赞");
}
//保存当前key
log.info("保存当前key:{}, {}, {}",dto.getArticleId(), user.getId(), dto);
cacheService.hPut(BehaviorConstants.LIKE_BEHAVIOR + dto.getArticleId().toString(), user.getId().toString(), JSON.toJSONString(dto));
} else {
//删除当前key
log.info("删除当前key:{}, {}",BehaviorConstants.LIKE_BEHAVIOR + dto.getArticleId().toString(), user.getId().toString());
}
return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
}
/**
* 检查参数
* @return
*/
private boolean checkParam(LikesBehaviorDto dto) {
if (dto.getType() > 2 || dto.getType() < 0 || dto.getOperation() > 1 || dto.getOperation() < 0) {
return true;
}
return false;
}
}
4.阅读
4.1实体类
ReadBehaviorDto:
package com.heima.model.behavior.dtos;
import lombok.Data;
@Data
public class ReadBehaviorDto {
// 文章、动态、评论等ID
Long articleId;
/**
* 阅读次数
*/
Short count;
/**
* 阅读时长(S)
*/
Integer readDuration;
/**
* 阅读百分比
*/
Short percentage;
/**
* 加载时间
*/
Short loadDuration;
}
4.2controller
ReadBehaviorController:
package com.heima.behavior.controller.v1;
import com.heima.behavior.service.ReadBehaviorService;
import com.heima.model.behavior.dtos.ReadBehaviorDto;
import com.heima.model.common.dtos.ResponseResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author Z-熙玉
* @version 1.0
*/
@RestController
@RequestMapping("/api/v1/read_behavior")
public class ReadBehaviorController {
@Autowired
private ReadBehaviorService readBehaviorService;
@PostMapping
public ResponseResult readBehavior(@RequestBody ReadBehaviorDto dto) {
return readBehaviorService.readBehavior(dto);
}
}
4.3service实现类
ReadBehaviorServiceImpl:
package com.heima.behavior.service.impl;
import com.alibaba.fastjson.JSON;
import com.heima.behavior.service.ReadBehaviorService;
import com.heima.common.constants.BehaviorConstants;
import com.heima.common.redis.CacheService;
import com.heima.model.behavior.dtos.ReadBehaviorDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.user.pojos.ApUser;
import com.heima.utils.thread.AppThreadLocalUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author Z-熙玉
* @version 1.0
*/
@Service
@Slf4j
public class ReadBehaviorServiceImpl implements ReadBehaviorService {
@Autowired
private CacheService cacheService;
/**
* 阅读统计
* @param dto
* @return
*/
@Override
public ResponseResult readBehavior(ReadBehaviorDto dto) {
//检查参数
if (dto == null || dto.getArticleId() == null) {
return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
}
//是否登录
ApUser user = AppThreadLocalUtil.getUser();
if (user == null) {
return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
}
//更新阅读次数
String readBehaviorJson = (String) cacheService.hGet(BehaviorConstants.READ_BEHAVIOR + dto.getArticleId().toString(), user.getId().toString());
if (StringUtils.isNotBlank(readBehaviorJson)) {
ReadBehaviorDto readBehaviorDto = JSON.parseObject(readBehaviorJson, ReadBehaviorDto.class);
dto.setCount((short) (readBehaviorDto.getCount() + dto.getCount()));
}
//保存当前key
log.info("保存当前key:{}, {}, {}", dto.getArticleId(), user.getId(), dto);
cacheService.hPut(BehaviorConstants.READ_BEHAVIOR + dto.getArticleId().toString(), user.getId().toString(), JSON.toJSONString(dto));
return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
}
}
5.不喜欢
5.1实体类
UnLikesBehaviorDto:
package com.heima.model.behavior.dtos;
import com.heima.model.common.annotation.IdEncrypt;
import lombok.Data;
@Data
public class UnLikesBehaviorDto {
// 文章ID
@IdEncrypt
Long articleId;
/**
* 不喜欢操作方式
* 0 不喜欢
* 1 取消不喜欢
*/
Short type;
}
5.2controller
UnlikesBehaviorController:
package com.heima.behavior.controller.v1;
import com.heima.behavior.service.UnlikesBehaviorService;
import com.heima.model.behavior.dtos.UnLikesBehaviorDto;
import com.heima.model.common.dtos.ResponseResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author Z-熙玉
* @version 1.0
*/
@RestController
@RequestMapping("/api/v1/un_likes_behavior")
public class UnlikesBehaviorController {
@Autowired
private UnlikesBehaviorService unlikesBehaviorService;
@PostMapping
public ResponseResult unLike(@RequestBody UnLikesBehaviorDto dto) {
return unlikesBehaviorService.unLike(dto);
}
}
5.3servicce实现类
package com.heima.behavior.service.impl;
import com.alibaba.fastjson.JSON;
import com.heima.behavior.service.UnlikesBehaviorService;
import com.heima.common.constants.BehaviorConstants;
import com.heima.common.redis.CacheService;
import com.heima.model.behavior.dtos.UnLikesBehaviorDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.user.pojos.ApUser;
import com.heima.utils.thread.AppThreadLocalUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author Z-熙玉
* @version 1.0
*/
@Service
@Slf4j
public class UnlikesBehaviorServiceImpl implements UnlikesBehaviorService {
@Autowired
private CacheService cacheService;
/**
* 不喜欢
* @param dto
* @return
*/
@Override
public ResponseResult unLike(UnLikesBehaviorDto dto) {
//校验参数
if (dto.getArticleId() == null) {
return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
}
//判断是否登录
ApUser user = AppThreadLocalUtil.getUser();
if (user == null) {
return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
}
//设置不喜欢与取消不喜欢
if (dto.getType() == 0) {
log.info("保存当前key:{}, {}, {}", dto.getArticleId(), user.getId(), dto);
cacheService.hPut(BehaviorConstants.UN_LIKE_BEHAVIOR + dto.getArticleId().toString(), user.getId().toString(), JSON.toJSONString(dto));
} else {
log.info("删除当前key:{}, {}, {}", dto.getArticleId(), user.getId(), dto);
cacheService.hDelete(BehaviorConstants.UN_LIKE_BEHAVIOR + dto.getArticleId().toString(), user.getId().toString());
}
return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
}
}
6.文章收藏
6.1实体类、常量类与mvc拦截器
CollectionBehaviorDto:
package com.heima.model.article.dtos;
import com.heima.model.common.annotation.IdEncrypt;
import lombok.Data;
import java.util.Date;
@Data
public class CollectionBehaviorDto {
// 文章、动态ID
@IdEncrypt
Long entryId;
/**
* 收藏内容类型
* 0文章
* 1动态
*/
Short type;
/**
* 操作类型
* 0收藏
* 1取消收藏
*/
Short operation;
Date publishedTime;
}
BehaviorConstants:
package com.heima.common.constants;
public class BehaviorConstants {
public static final String LIKE_BEHAVIOR="LIKE-BEHAVIOR-";
public static final String UN_LIKE_BEHAVIOR="UNLIKE-BEHAVIOR-";
public static final String COLLECTION_BEHAVIOR="COLLECTION-BEHAVIOR-";
public static final String READ_BEHAVIOR="READ-BEHAVIOR-";
public static final String APUSER_FOLLOW_RELATION="APUSER-FOLLOW-";
public static final String APUSER_FANS_RELATION="APUSER-FANS-";
}
拦截器还是直接拷贝即可
6.2controller
ApcollectionController
package com.heima.article.controller.v1;
import com.heima.article.service.ApCollectionService;
import com.heima.model.article.dtos.CollectionBehaviorDto;
import com.heima.model.common.dtos.ResponseResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author Z-熙玉
* @version 1.0
*/
@RestController
@RequestMapping("/api/v1/collection_behavior")
public class ApCollectionController {
@Autowired
private ApCollectionService apCollectionService;
@PostMapping
public ResponseResult collection(@RequestBody CollectionBehaviorDto dto) {
return apCollectionService.collection(dto);
}
}
6.3service实现类
ApCollectionServiceImpl:
package com.heima.article.service.impl;
import com.alibaba.fastjson.JSON;
import com.heima.article.service.ApCollectionService;
import com.heima.common.constants.BehaviorConstants;
import com.heima.common.redis.CacheService;
import com.heima.model.article.dtos.CollectionBehaviorDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.user.pojos.ApUser;
import com.heima.utils.thread.AppThreadLocalUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author Z-熙玉
* @version 1.0
*/
@Service
@Slf4j
public class ApCollectionServiceImpl implements ApCollectionService {
@Autowired
private CacheService cacheService;
/**
* 收藏文章
* @param dto
* @return
*/
@Override
public ResponseResult collection(CollectionBehaviorDto dto) {
//条件判断
if (dto == null || dto.getEntryId() == null) {
return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
}
//判断是否登录
ApUser user = AppThreadLocalUtil.getUser();
if (user == null) {
return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
}
//查询
String collectionJson = (String) cacheService.hGet(BehaviorConstants.COLLECTION_BEHAVIOR + user.getId(), dto.getEntryId().toString());
if (StringUtils.isNotBlank(collectionJson) && dto.getOperation() == 0) {
return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID,"文章已收藏");
}
//收藏
if (dto.getOperation() == 0) {
log.info("文章收藏,保存key:{},{},{}",dto.getEntryId(),user.getId().toString(), JSON.toJSONString(dto));
cacheService.hPut(BehaviorConstants.COLLECTION_BEHAVIOR + user.getId(), dto.getEntryId().toString(), JSON.toJSONString(dto));
} else {
//取消收藏
log.info("文章收藏,删除key:{},{},{}",dto.getEntryId(),user.getId().toString(), JSON.toJSONString(dto));
cacheService.hDelete(BehaviorConstants.COLLECTION_BEHAVIOR + user.getId(), dto.getEntryId().toString());
}
return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
}
}
7.加载文章行为 - 数据回显
7.1实体类
ArticleInfoDto:
package com.heima.model.article.dtos;
import com.heima.model.common.annotation.IdEncrypt;
import lombok.Data;
@Data
public class ArticleInfoDto {
// 设备ID
@IdEncrypt
Integer equipmentId;
// 文章ID
@IdEncrypt
Long articleId;
// 作者ID
@IdEncrypt
Integer authorId;
}
7.2controller
ArticleInfoController:
package com.heima.article.controller.v1;
import com.heima.article.service.ApArticleService;
import com.heima.model.article.dtos.ArticleInfoDto;
import com.heima.model.common.dtos.ResponseResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author Z-熙玉
* @version 1.0
*/
@RestController
@RequestMapping("/api/v1/article")
public class ArticleInfoController {
@Autowired
private ApArticleService apArticleService;
@PostMapping("/load_article_behavior")
public ResponseResult loadArticleBehavior(@RequestBody ArticleInfoDto dto) {
return apArticleService.loadArticleBehavior(dto);
}
}
7.3service实现类
ApArticleServiceImpl:
@Autowired
private CacheService cacheService;
/**
* 查看文章,数据回显
* @param dto
* @return
*/
@Override
public ResponseResult loadArticleBehavior(ArticleInfoDto dto) {
//检查参数
if (dto == null || dto.getArticleId() == null || dto.getAuthorId() == null) {
return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
}
boolean isfollow = false, islike = false, isunlike = false, iscollection = false;
ApUser user = AppThreadLocalUtil.getUser();
if (user != null) {
//喜欢行为
String likeBehaviorJson = (String) cacheService.hGet(BehaviorConstants.LIKE_BEHAVIOR + dto.getAuthorId().toString(), user.getId().toString());
if (StringUtils.isNotBlank(likeBehaviorJson)) {
islike = true;
}
//不喜欢的行为
String unLikeBehaviorJson = (String) cacheService.hGet(BehaviorConstants.UN_LIKE_BEHAVIOR + dto.getAuthorId().toString(), user.getId().toString());
if (StringUtils.isNotBlank(unLikeBehaviorJson)) {
isunlike = true;
}
//是否收藏
String collctionJson = (String) cacheService.hGet(BehaviorConstants.COLLECTION_BEHAVIOR+user.getId(),dto.getArticleId().toString());
if(StringUtils.isNotBlank(collctionJson)){
iscollection = true;
}
//是否关注
Double score = cacheService.zScore(BehaviorConstants.APUSER_FOLLOW_RELATION + user.getId(), dto.getAuthorId().toString());
System.out.println(score);
if(score != null){
isfollow = true;
}
}
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("isfollow", isfollow);
resultMap.put("islike", islike);
resultMap.put("isunlike", isunlike);
resultMap.put("iscollection", iscollection);
return ResponseResult.okResult(resultMap);
}
至此,day08,day09的实战部分全部结束了,给个三连支持一下孩子吧~,有问题评论区留言哦。