【黑马头条】-day09用户行为-点赞收藏关注阅读不喜欢-数据回显-精度丢失解决


文章目录

  • 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
dtodtobodytrueLikesBehaviorDtoLikesBehaviorDto
  articleId文章idfalselong
  operation0 点赞 1 取消点赞falseshort
  type0文章 1动态 2评论falseshort

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是否必须
dtodtobodytrue
  articleId文章idlongfalse
  count阅读次数intfalse

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
dtodtobodytrueUnLikesBehaviorDtoUnLikesBehaviorDto
  articleId文章idfalselong
  type0 不喜欢 1 取消不喜欢falseshort

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
dtodtobodytrueUserRelationDtoUserRelationDto
  articleId文章idfalselong
  authorId作者idfalseint
  operation0 关注 1 取消falseshort

关注需要在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
dtodtobodytrueCollectionBehaviorDtoCollectionBehaviorDto
  entryId文章idfalselong
  operation0收藏 1取消收藏falseshort
  publishedTime发布时间falsedate
  type0文章 1动态falseshort

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
dtodtobodytrueArticleInfoDtoArticleInfoDto
  articleId文章idfalselong
  authorId作者idfalseint

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号作者已关注

在这里插入图片描述

测试成功

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/545984.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

机器人方向控制中应用的磁阻角度传感芯片

磁阻传感器提供的输出信号几乎不受磁场变动、磁温度系数、磁传感器距离与位置变动影响&#xff0c;可以达到高准确度与高效能&#xff0c;因此相当适合各种要求严格的车用电子与工业控制的应用。所以它远比采用其它传感方法的器件更具有优势。 机器人的应用日渐广泛&#xff0…

ChatGPT们写高考作文会发生什么?

2023年的高考结束了&#xff0c;今年共有1291万考生参加了高考了&#xff0c;再次创造了历史参考人数之最。在高考中&#xff0c;要说什么最引人讨论&#xff0c;那高考作文当仁不让啊。今年随着ChatGPT的爆火&#xff0c;可谓是给文字工作者带来一大助力&#xff0c;如果让AI来…

2024腾讯一道笔试题--大小写字母移动

题目&#x1f357; 有一个字符数组,其中只有大写字母和小写字母,将小写字母移到前面, 大写字符移到后面,保持小写字母本身的顺序不变,大写字母本身的顺序不变, 注意,不要分配新的数组.(如:wCelOlME,变为wellCOME). 思路分析&#x1f357; 类似于冒泡排序&#xff0c;两两比较…

将本地项目上传到Github

首先安装git、创建github账号 1、创建一个新的仓库 2、创建SSH KEY。先看一下你C盘用户目录下有没有.ssh目录&#xff0c;有的话看下里面有没有id_rsa和id_rsa.pub这两个文件&#xff0c;有就跳到下一步&#xff0c;没有就通过下面命令创建。 ssh-keygen -t rsa -C "you…

做测试,不会接口测试怎么能行?

接口测试的测试点 功能测试&#xff1a;单接口功能、业务场景功能 性能测试&#xff1a;响应时长、错误率、吞吐量、服务器资源使用率 安全测试&#xff1a;敏感数据是否加密、SQL注入、其他 本篇文章以接口功能测试为主。 接口用例设计方法&#xff1a; 单接口测试用例设…

如何通过Linux pciehp sysfs接口控制PCIe Slot电源状态?-3

pciehp sysfs接口电源控制与NVME驱动卸载的区别 从NVMe SSD设计本身而言&#xff0c;当通过pciehp sysfs接口对PCIe插槽执行Power Off操作时&#xff0c;由于NVMe SSD作为PCIe设备&#xff0c;其电源供应是直接依赖于所连接的PCIe插槽提供的。当插槽电源被关闭时&#xff0c;会…

天工期刊投稿发表论文

《天工》杂志是由国家新闻出版总署批准&#xff0c;山西省科学技术协会主管、山西科技新闻出版传媒有限责任公司主办的工艺美术类专业期刊。杂志以“宣传中华工艺美术技艺&#xff0c;传播前沿工艺美术新成果&#xff0c;挖掘工艺美术人才&#xff0c;助推工美品牌打造”为办刊…

SpringCloudAlibaba之nacos的服务注册与发现

Nacos的服务注册与发现 照例放个妹子 本章节讲解nacos的服务注册与发现的简单使用 如图所示&#xff1a;按照图示搭建一个nacos作为服务注册中心的简单应用 创建provider服务提供者 创建nacos-discovery-provider模块引入依赖 <dependencies><dependency><…

vue3从精通到入门4:diff算法的实现

Vue 3 的 diff 算法相较于 Vue 2 有了一些改进和优化&#xff0c;主要是为了应对更复杂的组件结构和更高的性能需求。 以下是 Vue 3 diff 算法在处理列表更新时的大致步骤&#xff1a; 头头比较&#xff1a;首先&#xff0c;比较新旧列表的头节点&#xff08;即第一个节点&…

聚观早报 | 哪吒L上市定档;iPhone 16最新高清渲染图

聚观早报每日整理最值得关注的行业重点事件&#xff0c;帮助大家及时了解最新行业动态&#xff0c;每日读报&#xff0c;就读聚观365资讯简报。 整理丨Cutie 4月10日消息 哪吒L上市定档 iPhone 16最新渲染图 华为太空表与问界M9联动 蔚来万里长城加电风景线正式贯通 Red…

transformer架构详细详解

一、transformer的贡献 transformer架构的贡献&#xff1a;该架构只使用自注意力机制&#xff0c;没有使用RNN或卷积网络。且可以实现并行计算&#xff0c;加快模型训练速度。 &#xff08;将所有的循环层全部换成&#xff1a;multi-headed self-attention&#xff09; 二、t…

leetcode刷题日记之全排列

题目描述 题目解释 这个题类似于之前做的某一道题&#xff0c;其实算法还是要追踪到树的深度遍历&#xff0c;相当于便利叶子节点的路径记录。不过递归的过程就相当于件数根据树进行遍历了。 代码如下 class Solution:def permute(self, nums: List[int]) -> List[List[i…

fiddler常用操作汇总

1、过滤 2、查看数据包内容 3、弱网测试 弱网测试其实就是提前设置好一个值&#xff0c;在这个环境下进行测试就行了。 &#xff08;1&#xff09;进入定制规则页面&#xff1a; (2) 点击CtrlF调起搜索&#xff0c;在Find what 中输入300进行查找&#xff0c;更改上行、下行网…

(四)C++自制植物大战僵尸游戏启动流程

植物大战僵尸游戏开发教程专栏地址http://t.csdnimg.cn/ErelL 一、启动方式 鼠标左键单机VS2022上方工具栏中绿色三角按钮&#xff08;本地Windows调试器&#xff09;进行项目启动。第一次启动项目需要编译项目中所有代码文件&#xff0c;编译生成需要一定的时间。不同性能的电…

LPRNet车牌识别模型训练及CCPD数据集预处理

LPRNet车牌识别模型训练及CCPD数据集预处理 1 LPRNet车牌识别模型训练 1.1 源码:LPRNet_Pytorch-master 源码官网:GitHub - sirius-ai/LPRNet_Pytorch: Pytorch Implementation For LPRNet, A High Performance And Lightweight License Plate Recognition Framework. 链…

内网渗透-cobaltstrike之cs上线获取shell

cobaltstrike之cs上线获取shell 文章目录 cobaltstrike之cs上线获取shell前言一、什么是cobaltstrike二、cs上线获取shell 1.环境搭建 CS安装windows连接 2. cs上线获取shell 总结 前言 一、什么是cobaltstrike CobaltStrike是一款渗透测试神器&#xff0c;被业界人称为CS神器…

U盘有很多空间不见,看这篇能不能帮你解决

文章目录 概要整体架构流程 概要 我本来想在u盘上&#xff0c;安装一个ubuntu系统&#xff0c;结果一直安装失败&#xff0c;最后u盘空间还有好多没有了就是显示不出来了 整体架构流程 按住winx&#xff0c;会弹出以下界面 选择磁盘管理 然后会看到 这个就是你的u盘&…

工业物联网网关

在数字化浪潮席卷全球的今天&#xff0c;工业物联网&#xff08;IIoT&#xff09;作为连接物理世界与数字世界的桥梁&#xff0c;正在逐渐改变传统工业的面貌。而作为IIoT的核心枢纽&#xff0c;工业物联网网关发挥着至关重要的作用。今天&#xff0c;我们就来深入了解一下工业…

OpenHarmony实战开发-Axios获取解析网络数据。

介绍 本示例介绍使用第三方库的Axios获取GBK格式的网络数据时&#xff0c;通过util实现GBK转换UTF-8格式。该场景多用于需要转换编码格式的应用。 效果图预览 使用说明 直接进入页面就可获取GBK格式的用户名信息并进行解码操作。 实现思路 1.使用第三方库Axios获取网络数据…

基于51单片机的自行车测速里程码表设计( proteus仿真+程序+设计报告+原理图+讲解视频)

基于51单片机的自行车测速里程码表设计 1. 主要功能&#xff1a;2. 讲解视频&#xff1a;3. 仿真设计4. 程序代码5. 设计报告6. 原理图7. 设计资料内容清单资料下载链接&#xff1a; 基于51单片机的自行车测速里程码表设计( proteus仿真程序设计报告原理图讲解视频&#xff09;…