文章目录
- 1 long类型精度丢失问题
- 1.1 解决
- 1.2 导入jackson序列化工具
- 1.3 自定义注解
- 1.4 原理
- 1.5 测试
- 2 用户行为要求
- 3 创建微服务behavior
- 3.1 微服务创建
- 3.2 添加启动类
- 3.3 创建bootstrap.yml
- 3.4 在nacos中配置redis
- 3.5 引入redis依赖
- 3.6 更新minio
- 4 点赞
- 4.1 实体类LikesBehaviorDto
- 4.2 Redis的Hash值
- 4.3 用拦截器保存获取当前用户
- 4.4 Controller
- 4.5 Serivce
- 4.6 测试
- 5 阅读
- 5.1 实体类ReadBehaviorDto
- 5.2 Controller
- 5.3 Service
- 5.4 测试
- 6 不喜欢
- 6.1 实体类UnLikesBehaviorDto
- 6.2 Controller
- 6.3 Service
- 6.4 测试
- 7 关注与取消关注
- 7.1 实体类UserRelationDto
- 7.2 Controller
- 7.3 Service
- 7.4 测试
- 8 文章收藏
- 8.0 为文章微服务配置redis
- 8.1 实体类CollectionBehaviorDto
- 8.2 Controller
- 8.3 Service
- 8.4 测试
- 9 加载文章行为-数据回显
- 9.1 实体类ArticleInfoDto
- 9.2 Controller
- 9.3 Service
- 9.4 测试
1 long类型精度丢失问题
在数据库与网络传输的long类型的id传输中,long类型的id发生了精度丢失
1.1 解决
- 当后端响应给前端的数据中包含了id或者特殊标识(可自定义)的时候,把当前数据进行转换为String类型
- 当前端传递后后端的dto中有id或者特殊标识(可自定义)的时候,把当前数据转为Integer或Long类型。
特殊标识类说明:
IdEncrypt 自定义注解 作用在需要转换类型的字段属性上,用于非id的属性上 在model包下
1.2 导入jackson序列化工具
将jackson序列化工具导入heima-leadnews-common模块下的com.heima.common.jackson
因为是外来复制进来的,要想让spring进行管理,就需要将配置类导入src/main/resources/META-INF/spring.factories中
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.heima.common.exception.ExceptionCatch,\
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
1.3 自定义注解
将配置导入spring后,发现有个注解找不到
需要导入自定义注解
导入自定义注解到heima-leadnews-model模块中的com.heima.model.common.annotation.IdEncrypt
@JacksonAnnotation
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
public @interface IdEncrypt {
}
1.4 原理
在heima-leadnews-common模块下的com.heima.common.jackson.ConfusionSerializerModifier类中
public class ConfusionSerializerModifier extends BeanSerializerModifier {
@Override
public List<BeanPropertyWriter> changeProperties(SerializationConfig config,
BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) {
List<BeanPropertyWriter> newWriter = new ArrayList<>();
for(BeanPropertyWriter writer : beanProperties){
String name = writer.getType().getTypeName();
if(null == writer.getAnnotation(IdEncrypt.class) && !writer.getName().equalsIgnoreCase("id")){
newWriter.add(writer);
} else {
writer.assignSerializer(new ConfusionSerializer());
newWriter.add(writer);
}
}
return newWriter;
}
}
if(null == writer.getAnnotation(IdEncrypt.class) && !writer.getName().equalsIgnoreCase("id"))
如果是被IdEncrypt注解标注的或者为id字段的则被自动转为字符串序列化。
1.5 测试
重启heima-leadnews-artcile微服务
id已经加上双引号,转为字符串也就不会有精度丢失了。
2 用户行为要求
- 所有的行为数据,都存储到redis中
- 点赞、阅读、不喜欢需要专门创建一个微服务来处理数据,新建模块:heima-leadnews-behavior
- 关注需要在heima-leadnews-user微服务中实现
- 收藏与文章详情数据回显在heima-leadnews-article微服务中实现
3 创建微服务behavior
3.1 微服务创建
创建微服务heima-leadnews-behavior
3.2 添加启动类
@SpringBootApplication
public class BehaviorAppliction {
public static void main(String[] args) {
SpringApplication.run(BehaviorAppliction.class, args);
}
}
3.3 创建bootstrap.yml
创建bootstrap.yml配置nacos
server:
port: 51806
spring:
application:
name: leadnews-behavior
cloud:
nacos:
discovery:
server-addr: 192.168.204.129:8848
config:
server-addr: 192.168.204.129:8848
file-extension: yml
3.4 在nacos中配置redis
在nacos中创建leadnews-behavior配置中心,配置redis
因为文章相应的点赞收藏需要操作数据库,所以也需要配置数据库信息。
spring:
redis:
host: 192.168.204.129
password: leadnews
port: 6379
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/leadnews_admin?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false
username: root
password: 123sjbsjb
minio:
accessKey: minio
secretKey: minio123
bucket: leadnews
endpoint: http://192.168.204.129:9000
readPath: http://192.168.204.129:9000
3.5 引入redis依赖
为heima-leadnews-behavior模块引入redis依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- redis依赖commons-pool 这个依赖一定要添加 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
因为在之间已经将redis的工具类CacheService放入heima-leadnews-common的com.heima.common.redis下,并且交由spring管理,所以其他微服务可以直接注入CacheService使用redis。
3.6 更新minio
因为要进行回显,所以需要对静态html的文件在每次更新后进行重新生成静态文件。
在heima-leadnews-article模块中的com.heima.article.test中编写一个ArticleFreemarkerTest测试类,用于重新加载所有文件的minio的静态地址
@SpringBootTest(classes= ArticleApplication.class)
@RunWith(SpringRunner.class)
public class ArticleFreemarkerTest {
@Autowired
private ApArticleContentMapper apArticleContentMapper;
@Autowired
private Configuration configuration;
@Autowired
private FileStorageService fileStorageService;
@Autowired
private ApArticleService apArticleService;
@Test
public void testAllFreemarker() throws Exception {
//1.获取所有文章id
ApArticle apArticle = new ApArticle();
List<ApArticle> apArticles = apArticleService.list();
for (ApArticle article : apArticles) {
//2.获取文章内容
ApArticleContent apArticleContent = apArticleContentMapper
.selectOne(Wrappers
.<ApArticleContent>lambdaQuery()
.eq(ApArticleContent::getArticleId, article.getId()));
if(apArticleContent!=null&& StringUtils.isNotBlank(apArticleContent.getContent())){
//3.文章内容通过freemarker生成静态html页面
Template template = configuration.getTemplate("article.ftl");
//3.1 创建模型
Map<String,Object> content=new HashMap();
content.put("content", JSONArray.parseArray(apArticleContent.getContent()));
//3.2 输出流
StringWriter writer = new StringWriter();
//3.3 合成方法
template.process(content,writer);
//4.把静态页面上传到minio
//4.1 文件流
InputStream inputStream = new ByteArrayInputStream(writer.toString().getBytes());
String path = fileStorageService.uploadHtmlFile("",apArticleContent.getArticleId()+".html",inputStream);
//5.把静态页面的路径保存到数据库
apArticleService.update(Wrappers
.<ApArticle>lambdaUpdate()
.eq(ApArticle::getId,apArticleContent.getArticleId())
.set(ApArticle::getStaticUrl,path));
}
}
}
}
4 点赞
接口地址:/api/v1/likes_behavior
请求方式:POST
请求参数:
参数名称 | 参数说明 | in | 是否必须 | 数据类型 | schema |
---|---|---|---|---|---|
dto | dto | body | true | LikesBehaviorDto | LikesBehaviorDto |
articleId | 文章id | false | long | ||
operation | 0 点赞 1 取消点赞 | false | short | ||
type | 0文章 1动态 2评论 | false | short |
4.1 实体类LikesBehaviorDto
在heima-leadnews-model中创建com.heima.model.behavior.dtos.LikesBehaviorDto类
@Data
public class LikesBehaviorDto {
// 文章、动态、评论等ID
Long articleId;
/**
* 喜欢内容类型
* 0文章
* 1动态
* 2评论
*/
Short type;
/**
* 喜欢操作方式
* 0 点赞
* 1 取消点赞
*/
Short operation;
}
4.2 Redis的Hash值
在heima-leadnew-common中创建com.heima.common.constants.BehaviorConstants类,用于保存key
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-";
}
4.3 用拦截器保存获取当前用户
在heima-leadnews-behavior中创建com.heima.behavior.interceptor.AppTokenInterceptor类
public class AppTokenInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String userId = request.getHeader("userId");
if(userId != null){
//存入到当前线程中
ApUser apUser = new ApUser();
apUser.setId(Integer.valueOf(userId));
AppThreadLocalUtil.setUser(apUser);
}
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
AppThreadLocalUtil.clear();
}
}
创建com.heima.behavior.config.WebMvcConfig将拦截器AppTokenInterceptor加入当前拦截器注册器里
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AppTokenInterceptor()).addPathPatterns("/**");
}
}
4.4 Controller
在heima-leadnews-behavior中创建com.heima.behavior.controller.v1.ApLikesBehaviorController
@RestController
@RequestMapping("/api/v1/likes_behavior")
public class ApLikesBehaviorController {
@Autowired
private ApLikesBehaviorService apLikesBehaviorService;
@PostMapping
public ResponseResult like(@RequestBody LikesBehaviorDto dto) {
return apLikesBehaviorService.like(dto);
}
}
4.5 Serivce
接口
public interface ApLikesBehaviorService {
/**
* 存储喜欢数据
* @param dto
* @return
*/
public ResponseResult like(LikesBehaviorDto dto);
}
实现
@Service
@Transactional
@Slf4j
public class ApLikesBehaviorServiceImpl implements ApLikesBehaviorService {
@Autowired
private CacheService cacheService;
@Override
public ResponseResult like(LikesBehaviorDto dto) {
//1.检查参数
if (dto == null || dto.getArticleId() == null || checkParam(dto)) {
return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
}
//2.是否登录
ApUser user = AppThreadLocalUtil.getUser();
if (user == null) {
return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
}
//3.点赞 保存数据
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:{}, {}", dto.getArticleId(), user.getId());
cacheService.hDelete(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.6 测试
启动微服务
先登录获取token
获取token为
eyJhbGciOiJIUzUxMiIsInppcCI6IkdaSVAifQ.H4sIAAAAAAAAADWLQQqAMAwE_5KzhcZGI_4mpRUrCIVUUMS_Gw_uaYdhbthagRkWsiUUF8kvjqbRuzhycP3UJ-JMiAmhgyINZmQMyJ6H0IEe0Wq9tOX986qGay67GMmRjKRW-_msf0nhK4s5el4Gao0hgAAAAA.GnAVSmGCq388UxNUJVSr87uSfrQ6QSD0RmRtfeDDvhMecu5Ylj_KSOAR29H40rFi5L-Fzhd2kRkj5ZxQTBpyEQ
找一个文章点赞
点赞一下这个文章吧 id 1778978497432260609
请求地址http://localhost:51601/behavior/api/v1/likes_behavior
请求体:0是点赞
{
"articleId": 1778978497432260609,
"operation": 0,
"type": 0
}
把刚刚的token添加到headers中
发送post请求
请求成功,查看redis
成功保存
5 阅读
接口地址:/api/v1/read_behavior
请求方式:POST
参数名称 | 参数说明 | in | 是否必须 |
---|---|---|---|
dto | dto | body | true |
articleId | 文章id | long | false |
count | 阅读次数 | int | false |
5.1 实体类ReadBehaviorDto
在heima-leadnews-model中创建com.heima.model.behavior.dtos.ReadBehaviorDto类
@Data
public class ReadBehaviorDto {
// 文章、动态、评论等ID
Long articleId;
/**
* 阅读次数
*/
Short count;
}
5.2 Controller
在heima-leadnews-behavior中创建com.heima.behavior.controller.v1.ApReadBehaviorController
@RestController
@RequestMapping("/api/v1/read_behavior")
public class ApReadBehaviorController {
@Autowired
private ApReadBehaviorService apReadBehaviorService;
@PostMapping
public ResponseResult readBehavior(@RequestBody ReadBehaviorDto dto) {
return apReadBehaviorService.readBehavior(dto);
}
}
5.3 Service
接口
public interface ApReadBehaviorService {
/**
* 保存阅读行为
* @param dto
* @return
*/
public ResponseResult readBehavior(ReadBehaviorDto dto);
}
实现
@Service
@Transactional
@Slf4j
public class ApReadBehaviorServiceImpl implements ApReadBehaviorService {
@Autowired
private CacheService cacheService;
@Override
public ResponseResult readBehavior(ReadBehaviorDto dto) {
//1.检查参数
if (dto == null || dto.getArticleId() == null) {
return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
}
//2.是否登录
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.4 测试
请求体
{
"articleId": 1778978497432260609,
"count": 10
}
查看redis
6 不喜欢
接口地址:/api/v1/un_likes_behavior
请求方式:POST
请求参数:
参数名称 | 参数说明 | in | 是否必须 | 数据类型 | schema |
---|---|---|---|---|---|
dto | dto | body | true | UnLikesBehaviorDto | UnLikesBehaviorDto |
articleId | 文章id | false | long | ||
type | 0 不喜欢 1 取消不喜欢 | false | short |
6.1 实体类UnLikesBehaviorDto
在heima-leadnews-model中创建com.heima.model.behavior.dtos.UnLikesBehaviorDto类
@Data
public class UnLikesBehaviorDto {
// 文章ID
@IdEncrypt
Long articleId;
/**
* 不喜欢操作方式
* 0 不喜欢
* 1 取消不喜欢
*/
Short type;
}
6.2 Controller
在heima-leadnews-behavior中创建com.heima.behavior.controller.v1.ApUnlikesBehaviorController
@RestController
@RequestMapping("/api/v1/un_likes_behavior")
public class ApUnlikesBehaviorController {
@Autowired
private ApUnlikesBehaviorService apUnlikesBehaviorService;
@PostMapping
public ResponseResult unLike(@RequestBody UnLikesBehaviorDto dto) {
return apUnlikesBehaviorService.unLike(dto);
}
}
6.3 Service
接口
public interface ApUnlikesBehaviorService {
/**
* 不喜欢
* @param dto
* @return
*/
public ResponseResult unLike(UnLikesBehaviorDto dto);
}
实现
@Slf4j
@Service
public class ApUnlikesBehaviorServiceImpl implements ApUnlikesBehaviorService {
@Autowired
private CacheService cacheService;
@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.4 测试
请求体
{
"articleId": 1778978497432260609,
"type": 0
}
查看redis
7 关注与取消关注
接口地址:/api/v1/user/user_follow
请求方式:POST
请求参数:
参数名称 | 参数说明 | in | 是否必须 | 数据类型 | schema |
---|---|---|---|---|---|
dto | dto | body | true | UserRelationDto | UserRelationDto |
articleId | 文章id | false | long | ||
authorId | 作者id | false | int | ||
operation | 0 关注 1 取消 | false | short |
关注需要在heima-leadnews-user微服务中实现
7.1 实体类UserRelationDto
在heima-leadnews-model中创建com.heima.model.user.dtos.UserRelationDto类
@Data
public class UserRelationDto {
// 文章作者ID
@IdEncrypt
Integer authorId;
// 文章id
@IdEncrypt
Long articleId;
/**
* 操作方式
* 0 关注
* 1 取消
*/
Short operation;
}
7.2 Controller
在heima-leadnews-user中创建com.heima.user.controller.v1.UserRelationController类
@RestController
@RequestMapping("/api/v1/user")
public class UserRelationController {
@Autowired
private ApUserRelationService apUserRelationService;
@PostMapping("/user_follow")
public ResponseResult follow(@RequestBody UserRelationDto dto){
return apUserRelationService.follow(dto);
}
}
7.3 Service
接口
public interface ApUserRelationService {
/**
* 用户关注/取消关注
* @param dto
* @return
*/
public ResponseResult follow(UserRelationDto dto);
}
实现
@Service
public class ApUserRelationServiceImpl implements ApUserRelationService {
@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_FOLLOW_RELATION + apUserId, followUserId.toString());
cacheService.zRemove(BehaviorConstants.APUSER_FANS_RELATION + followUserId, apUserId.toString());
}
return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
}
}
7.4 测试
当前登录的用户id是4
关注文章的作者id是1102
请求体:
{
"articleId": 1778978497432260609,
"authorId": 1102,
"operation": 0
}
查看redis,写入成功
8 文章收藏
收藏与文章详情数据回显在heima-leadnews-article微服务中实现
接口地址:/api/v1/collection_behavior
请求方式:POST
参数名称 | 参数说明 | in | 是否必须 | 数据类型 | schema |
---|---|---|---|---|---|
dto | dto | body | true | CollectionBehaviorDto | CollectionBehaviorDto |
entryId | 文章id | false | long | ||
operation | 0收藏 1取消收藏 | false | short | ||
publishedTime | 发布时间 | false | date | ||
type | 0文章 1动态 | false | short |
8.0 为文章微服务配置redis
在文章微服务的nacos配置中添加redis配置
redis:
host: 192.168.204.129
password: leadnews
port: 6379
8.1 实体类CollectionBehaviorDto
在heima-leadnews-model中创建com.heima.model.article.dtos.CollectionBehaviorDto类
@Data
public class CollectionBehaviorDto {
// 文章、动态ID
@IdEncrypt
Long entryId;
/**
* 收藏内容类型
* 0文章
* 1动态
*/
Short type;
/**
* 操作类型
* 0收藏
* 1取消收藏
*/
Short operation;
Date publishedTime;
}
8.2 Controller
在heima-leadnews-user中创建com.heima.article.controller.v1.ApCollectionController类
@RestController
@RequestMapping("/api/v1/collection_behavior")
public class ApCollectionController {
@Autowired
private ApCollectionService apCollectionService;
@PostMapping
public ResponseResult collection(@RequestBody CollectionBehaviorDto dto) {
return apCollectionService.collection(dto);
}
}
8.3 Service
接口
public interface ApCollectionService {
/**
* 收藏
* @param dto
* @return
*/
public ResponseResult collection(CollectionBehaviorDto dto);
}
实现
@Service
@Slf4j
public class ApCollectionServiceImpl implements ApCollectionService {
@Autowired
private CacheService cacheService;
@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);
}
}
8.4 测试
请求体
{
"entryId": 1778978497432260609,
"operation": 0,
"publishedTime": 1712976151,
"type": 0
}
查看redis
9 加载文章行为-数据回显
接口地址:/api/v1/article/load_article_behavior
请求方式:POST
请求参数:
参数名称 | 参数说明 | in | 是否必须 | 数据类型 | schema |
---|---|---|---|---|---|
dto | dto | body | true | ArticleInfoDto | ArticleInfoDto |
articleId | 文章id | false | long | ||
authorId | 作者id | false | int |
9.1 实体类ArticleInfoDto
@Data
public class ArticleInfoDto {
// 设备ID
@IdEncrypt
Integer equipmentId;
// 文章ID
@IdEncrypt
Long articleId;
// 作者ID
@IdEncrypt
Integer authorId;
}
9.2 Controller
在heima-leadnews-model中创建com.heima.article.controller.v1.ArticleInfoController类
@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);
}
}
9.3 Service
接口
public interface ApArticleService extends IService<ApArticle>{
/**
* 加载文章列表
* @param dto
* @param type 1 加载更多 2 加载最新
* @return
*/
public ResponseResult load(ArticleHomeDto dto, Short type);
/**
* 保存文章
* @param dto
* @return
*/
public ResponseResult saveArticle(ArticleDto dto);
/**
* 加载文章详情 数据回显
* @param dto
* @return
*/
public ResponseResult loadArticleBehavior(ArticleInfoDto dto);
}
实现,把所有redis中存储的用户行为做成map返回
@Autowired
private CacheService cacheService;
@Override
public ResponseResult loadArticleBehavior(ArticleInfoDto dto) {
//0.检查参数
if (dto == null || dto.getArticleId() == null || dto.getAuthorId() == null) {
return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
}
//{ "isfollow": true, "islike": true,"isunlike": false,"iscollection": true }
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.getArticleId().toString(), user.getId().toString());
if(org.apache.commons.lang3.StringUtils.isNotBlank(likeBehaviorJson)){
islike = true;
}
//不喜欢的行为
String unLikeBehaviorJson = (String) cacheService.hGet(BehaviorConstants.UN_LIKE_BEHAVIOR + dto.getArticleId().toString(), user.getId().toString());
if(org.apache.commons.lang3.StringUtils.isNotBlank(unLikeBehaviorJson)){
isunlike = true;
}
//是否收藏
String collctionJson = (String) cacheService.hGet(BehaviorConstants.COLLECTION_BEHAVIOR+user.getId(),dto.getArticleId().toString());
if(org.apache.commons.lang3.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);
}
9.4 测试
请求体:
{
"articleId": 1778978497432260609,
"authorId": 1102
}
针对当前id为4的用户,对1778978497432260609文章已收藏已点赞已不喜欢(感觉怪怪的,虽然点赞和不喜欢并不冲突),对于1102号作者已关注
测试成功