热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

SpringBoot实现物品点赞功能

这篇文章主要介绍了SpringBoot物品点赞功能实现,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

前后端分离项目–二手交易平台小程序

SpringBoot----物品收藏功能实现
SpringBoot----评论回复功能实现(数据库设计)
SpringBoot----文件(图片)上传与显示(下载)

点赞

这个功能耗费了我挺多时间,简单实现很简单,就++ – .但是还是感觉这种点赞是一个高频率的请求,而且搜的时候我看都是使用redis做缓存。b站也搜到一个视频来着,也是一样的。

效果:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

功能:

首先还是一个先发请求返回数据,但是先数据存到了redis中,然后使用springboot定时任务每隔一定时间将数据存到mysql中。这样可以防止redis挂掉之后数据丢失。

数据库设计:

在这里插入图片描述

MySQL使用了一张表和另外几张表的一个字段,一张存放点赞信息,就是谁点赞了谁在啥时候。字段存放点赞数量。就是物品信息表。评论表这些。
-

在这里插入图片描述

redis,使用的是hash数据结构,redis_liked存放点赞数据,redis_liked_count存放点赞数量数据。

解释 :

对于 “1::字符串::1 ” 这个是一种存放方式,前面1为objid就是被点赞物品或者评论id,字符串为微信openid每个用户唯一id,后面1为类型区分点赞的是物品还是主评论,子评论。

对于 "\"0\"" 这个数据则是点赞的状态,1为点赞0为取消点赞对于"1::1"这个前面1是objid就是物品或者子、主评论id,后面则是区别是哪个类型。“0”就是点赞数量。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述 

后台代码:

前端就发like或者取消unlike请求

package com.w.wx.controller;

import com.w.wx.domain.Msg;
import com.w.wx.service.impls.RedisServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
@RequestMapping("/wx/liked")
public class LikedContro {

    @Autowired
    private RedisServiceImpl redisService;

    /**
     * 保存点赞数据到redis
     * 点赞数+1
     * 同一个不能点赞两次
     * @param objId
     * @param openid
     * @param type
     * @return
     */
    @RequestMapping("like")
    public Msg saveLikedToRedis(Integer objId,String openid , String type){

        redisService.incrementLikedCount(objId, type, openid);

        redisService.saveLikedToRedis(objId,openid,type);

        int OneInfoCount= redisService.getOneInfoCount(objId, type);
        return Msg.success().add("count",oneInfoCount);
    }

    @RequestMapping("unlike")
    public  Msg decrementLikedCount(Integer objId,String openid,String type){
        redisService.decrementLikedCount(objId,type,openid);
        redisService.unlikeFromRedis(objId,openid,type);

        int OneInfoCount= redisService.getOneInfoCount(objId, type);
        return Msg.success().add("count",oneInfoCount);
    }
	
	//恢复redis
    @RequestMapping("restore")
    public Msg restoreRedisCountInfo(){
        redisService.savaInfoFromDb2Re(0);
        redisService.savaInfoFromDb2Re(1);
        redisService.savaInfoFromDb2Re(2);
        return Msg.success();
    }
}

操作redis代码

package com.w.wx.service.impls;

import com.w.wx.mapper.LikedMapper;
import com.w.wx.domain.Liked;
import com.w.wx.service.ImagesService;
import com.w.wx.service.RedisService;
import com.w.wx.utils.RedisKeyUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class RedisServiceImpl implements RedisService {

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private LikedServiceImpl likedService;
    @Autowired
    private ImagesService imagesService;

    /**
     * 保存数据到redis
     * @param objId
     * @param openid
     * @param type
     */
    @Override
    public void saveLikedToRedis(Integer objId, String openid,String type) {

        imagesService.addLikedNotice(objId, openid,type);
        String likedKey = RedisKeyUtils.getLikedKey("" + objId, openid,type);
        redisTemplate.opsForHash().put(RedisKeyUtils.MAP_KEY_USER_LIKED,likedKey, "1");
    }

    /**
     * 取消点赞
     * @param objId
     * @param openid
     * @param type
     */
    @Override
    public void unlikeFromRedis(Integer objId, String openid,String type) {
        String likedKey = RedisKeyUtils.getLikedKey("" + objId, openid,type);
        redisTemplate.opsForHash().put(RedisKeyUtils.MAP_KEY_USER_LIKED,likedKey, "0");
    }

    /**
     * 删除数据,没有用到
     * @param objId
     * @param openid
     * @param type
     */
    @Override
    public void deleteFromRedis(Integer objId, String openid,String type) {
        String key = RedisKeyUtils.getLikedKey("" + objId, openid,type);
        redisTemplate.opsForHash().delete(RedisKeyUtils.MAP_KEY_USER_LIKED, key);
    }

    /**
     * 自增,点赞数++
     * @param objId
     * @param type
     * @param openid
     * @return
     */
    @Override
    public Long incrementLikedCount(Integer objId,String type, String openid) {
        String key = RedisKeyUtils.getLikedKey("" + objId,type);
        String likedKey = RedisKeyUtils.getLikedKey("" + objId, openid,type);
        //根据定时器时长有延迟
//        if(likedMapper.selectByObjIdAndOpenid(objId,openid,Integer.valueOf(type)).getLikeStatus()==0){
//            redisTemplate.opsForHash().increment(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, key, 1);
//        }

        //防止重复点赞
        if("0".equals(redisTemplate.opsForHash().get(RedisKeyUtils.MAP_KEY_USER_LIKED,likedKey))
                || redisTemplate.opsForHash().get(RedisKeyUtils.MAP_KEY_USER_LIKED,likedKey) == null){

           return redisTemplate.opsForHash().increment(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, key, 1);
        }

        return null;
    }

    @Override
    public void decrementLikedCount(Integer objId,String type, String openid) {
        String key = RedisKeyUtils.getLikedKey("" + objId,type);
        String likedKey = RedisKeyUtils.getLikedKey("" + objId, openid,type);
//        if(likedMapper.selectByObjIdAndOpenid(objId,openid,Integer.valueOf(type)).getLikeStatus()==1){
//            redisTemplate.opsForHash().increment(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, key, -1);
//        }

        if("1".equals(redisTemplate.opsForHash().get(RedisKeyUtils.MAP_KEY_USER_LIKED,likedKey))){
            redisTemplate.opsForHash().increment(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, key, -1);
        }
    }

    /**
     * 获取redis中存放的点赞数据然后存放到mysql做持久化
     * @return
     */
    @Override
    public List getLikedDataFromRedis() {
        Cursor cursor = redisTemplate.opsForHash().scan(RedisKeyUtils.MAP_KEY_USER_LIKED, ScanOptions.NONE);
        List list = new ArrayList<>();
        while (cursor.hasNext()){
            Map.Entry entry = cursor.next();
            String key = (String) entry.getKey();

            String[] split = key.split("::");
            int status =  Integer.parseInt((String) entry.getValue());


            Liked like = new Liked();
            like.setObjId(Integer.valueOf(split[0]));
            like.setUserOpenid(split[1]);
            like.setType(Integer.valueOf(split[2]));
            like.setLikeStatus(status);

            list.add(like);

            //存到 list 后从 Redis 中删除
           // redisTemplate.opsForHash().delete(RedisKeyUtils.MAP_KEY_USER_LIKED, key);
        }

        return list;
    }

    //获取redis中点赞数量
    @Override
    public Cursor getLikedCountFromRedis() {
        Cursor cursor = redisTemplate.opsForHash().scan(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, ScanOptions.NONE);
        //redisTemplate.opsForHash().delete(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT);
        return cursor;
    }

    @Override
    public int getOneInfoCount(Integer objId, String type) {
        String key = RedisKeyUtils.getLikedKey("" + objId,type);
        return (int)redisTemplate.opsForHash().get(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT,key);
    }

    public void saveCountInfo(Integer objId,Integer type,Integer count){
        String key = RedisKeyUtils.getLikedKey("" + objId,""+type);
        redisTemplate.opsForHash().put(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT,key,count);
    }

    //redis挂掉后通过mysql中数据恢复redis
    @Override
    public void savaInfoFromDb2Re(Integer type) {
        List> likeds = likedService.selectLikedInfoByType(type);
        if (likeds.isEmpty()||likeds.equals("")){
            return;
        }

        Iterator> it = likeds.listIterator();
        while(it.hasNext()){
            Map map = it.next();
            Integer objId =  (Integer) map.get("objId");
            Integer count =  Integer.parseInt(map.get("num_liked").toString());
            log.info("objId:"+objId+"count:"+count+"type:"+type);
            saveCountInfo(objId,type,count);
        }
    }
}

操作mysql代码

package com.w.wx.service.impls;

import com.w.wx.mapper.CommentsInfoMapper;
import com.w.wx.mapper.CommentsReplyMapper;
import com.w.wx.mapper.GoodsMapper;
import com.w.wx.mapper.LikedMapper;
import com.w.wx.domain.CommentsInfo;
import com.w.wx.domain.Liked;
import com.w.wx.service.LikedService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.Cursor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Timestamp;
import java.util.*;

@Service
@Slf4j

public class LikedServiceImpl implements LikedService {

    @Autowired
    private RedisServiceImpl redisService;
    @Autowired
    private LikedMapper likedMapper;
    @Autowired
    private CommentsInfoMapper commentsInfoMapper;
    @Autowired
    private CommentsReplyMapper commentsReplyMapper;
    @Autowired
    private GoodsMapper goodsMapper;

    /**
     * 将缓存中点赞记录持久化到数据库
     */
    @Override
    @Transactional
    public void transLikedFromRedisToDB() {
        List likeds = redisService.getLikedDataFromRedis();

        for (Liked like : likeds) {
            Date date = new Date();
            Timestamp timestamp = new Timestamp(date.getTime());
            //首先判断之前是否有
            Liked liked = likedMapper.selectByObjIdAndOpenid(like.getObjId(),like.getUserOpenid(),like.getType());
            if(liked==null ){
                //没有则新增
                like.setCreateTime(timestamp);
                likedMapper.insert(like);
            }else{
                //有则更新
                 likedMapper.updateByPrimaryKey(liked.getLikeId(),like.getLikeStatus(),timestamp);
            }
        }
    }

    /**
     * 将点赞数量持久化到数据库
     */
    @Override
    @Transactional
    public void transLikedCountFromRedisToDB() {
        Cursor cursor = redisService.getLikedCountFromRedis();
        while (cursor.hasNext()){
            Map.Entry map = cursor.next();
            String key = (String)map.getKey();
            //分离出objId和type
            String[] split = key.split("::");
            int type =Integer.parseInt(split[1]);
            int objId = Integer.parseInt(split[0]);
            int likeNum = (Integer) map.getValue();
            if ( type == 1){
                //为主评论
                commentsInfoMapper.updateByPrimaryKey(objId,likeNum);

            }else if(type == 2){
                //为子评论
                commentsReplyMapper.updateByPrimaryKey(objId,likeNum);
            }else{
                //为物品
                goodsMapper.updateGoodsLikeSum(objId,likeNum);
            }
        }
    }

    @Override
    public List> selectLikedInfoByType(Integer type) {
        return likedMapper.selectLikedInfoByType(type);
    }
}

工具类

package com.w.wx.utils;

public class RedisKeyUtils {
    //保存用户点赞数据的key
    public static final String MAP_KEY_USER_LIKED = "redis_liked";
    //保存用户被点赞数量的key
    public static final String MAP_KEY_USER_LIKED_COUNT = "redis_liked_count";

    /**
     * 拼接被点赞的用户id和点赞的人的id作为key。格式 222222::333333::1
     * @param likedUserId 被点赞的人id
     * @param likedPostId 点赞的人的id
     * @return
     */
    public static String getLikedKey(String likedUserId, String likedPostId,String type){
        StringBuilder builder = new StringBuilder();
        builder.append(likedUserId);
        builder.append("::");
        builder.append(likedPostId);
        builder.append("::");
        builder.append(type);
        return builder.toString();
    }

    public static String getLikedKey(String likedUserId,String type){
        StringBuilder builder = new StringBuilder();
        builder.append(likedUserId);
        builder.append("::");
        builder.append(type);
        return builder.toString();
    }

}

定时任务配置类

package com.w.wx.config;

import com.w.wx.utils.LikeTask;
import org.quartz.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@Configuration
public class QuartzConfig {
    private static final String LIKE_TASK_IDENTITY = "LikeTaskQuartz";

    @Bean
    public JobDetail quartzDetail(){
        return JobBuilder.newJob(LikeTask.class).withIdentity(LIKE_TASK_IDENTITY).storeDurably().build();
    }

    @Bean
    public Trigger quartzTrigger(){
        SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
//                .withIntervalInSeconds(5)  //设置时间周期单位秒
                .withIntervalInHours(2)  //两个小时执行一次
                .repeatForever();
        return TriggerBuilder.newTrigger().forJob(quartzDetail())
                .withIdentity(LIKE_TASK_IDENTITY)
                .withSchedule(scheduleBuilder)
                .build();
    }
}

定时任务工具类

package com.w.wx.utils;

import com.w.wx.service.LikedService;
import com.w.wx.service.impls.LikedServiceImpl;
import lombok.extern.slf4j.Slf4j;

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;

import java.text.SimpleDateFormat;
import java.util.Date;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class LikeTask extends QuartzJobBean {
    @Autowired
    LikedServiceImpl likedService;

    private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {

        log.info("LikeTask-------- {}", sdf.format(new Date()));

        //将 Redis 里的点赞信息同步到数据库里
        likedService.transLikedFromRedisToDB();
        likedService.transLikedCountFromRedisToDB();

    }
}

参考:

springboot如何实现点赞功能
点赞功能的实现及Springboot定时器的应用

还有好多,第一页搜出来的基本都看过,第一次搞真心不会。。。
f12去看看csdn点赞,会发现点文章的赞会有点赞量的返回。点评论的赞就没

在这里插入图片描述
在这里插入图片描述

哔哩哔哩就看不懂了!!!

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

到此这篇关于SpringBoot物品点赞功能实现的文章就介绍到这了,更多相关SpringBoot点赞内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!


推荐阅读
  • 面试经验分享:华为面试四轮电话面试、一轮笔试、一轮主管视频面试、一轮hr视频面试
    最近有朋友去华为面试,面试经历包括四轮电话面试、一轮笔试、一轮主管视频面试、一轮hr视频面试。80%的人都在第一轮电话面试中失败,因为缺乏基础知识。面试问题涉及 ... [详细]
  • 篇首语:本文由编程笔记#小编为大家整理,主要介绍了软件测试知识点之数据库压力测试方法小结相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 分享css中提升优先级属性!important的用法总结
    web前端|css教程css!importantweb前端-css教程本文分享css中提升优先级属性!important的用法总结微信门店展示源码,vscode如何管理站点,ubu ... [详细]
  • 一次上线事故,30岁+的程序员踩坑经验之谈
    本文主要介绍了一位30岁+的程序员在一次上线事故中踩坑的经验之谈。文章提到了在双十一活动期间,作为一个在线医疗项目,他们进行了优惠折扣活动的升级改造。然而,在上线前的最后一天,由于大量数据请求,导致部分接口出现问题。作者通过部署两台opentsdb来解决问题,但读数据的opentsdb仍然经常假死。作者只能查询最近24小时的数据。这次事故给他带来了很多教训和经验。 ... [详细]
  • 本文介绍了关系型数据库和NoSQL数据库的概念和特点,列举了主流的关系型数据库和NoSQL数据库,同时描述了它们在新闻、电商抢购信息和微博热点信息等场景中的应用。此外,还提供了MySQL配置文件的相关内容。 ... [详细]
  • 2021最新总结网易/腾讯/CVTE/字节面经分享(附答案解析)
    本文分享作者在2021年面试网易、腾讯、CVTE和字节等大型互联网企业的经历和问题,包括稳定性设计、数据库优化、分布式锁的设计等内容。同时提供了大厂最新面试真题笔记,并附带答案解析。 ... [详细]
  • 旁路|发生_Day749.旁路缓存:Redis是如何工作的Redis 核心技术与实战
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了Day749.旁路缓存:Redis是如何工作的-Redis核心技术与实战相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 负载均衡_Nginx反向代理动静分离负载均衡及rewrite隐藏路径详解(Nginx Apache MySQL Redis)–第二部分
    nginx反向代理、动静分离、负载均衡及rewrite隐藏路径详解 ... [详细]
  • 推荐一个ASP的内容管理框架(ASP Nuke)的优势和适用场景
    本文推荐了一个ASP的内容管理框架ASP Nuke,并介绍了其主要功能和特点。ASP Nuke支持文章新闻管理、投票、论坛等主要内容,并可以自定义模块。最新版本为0.8,虽然目前仍处于Alpha状态,但作者表示会继续更新完善。文章还分析了使用ASP的原因,包括ASP相对较小、易于部署和较简单等优势,适用于建立门户、网站的组织和小公司等场景。 ... [详细]
  • 本文介绍了在Win10上安装WinPythonHadoop的详细步骤,包括安装Python环境、安装JDK8、安装pyspark、安装Hadoop和Spark、设置环境变量、下载winutils.exe等。同时提醒注意Hadoop版本与pyspark版本的一致性,并建议重启电脑以确保安装成功。 ... [详细]
  • 达人评测 酷睿i5 12450h和锐龙r7 5800h选哪个好 i512450h和r75800h对比
    本文介绍了达人评测酷睿i5 12450h和锐龙r7 5800h选哪个好的相关知识,包括两者的基本配置和重要考虑点。希望对你在选择时提供一定的参考价值。 ... [详细]
  • 一句话解决高并发的核心原则
    本文介绍了解决高并发的核心原则,即将用户访问请求尽量往前推,避免访问CDN、静态服务器、动态服务器、数据库和存储,从而实现高性能、高并发、高可扩展的网站架构。同时提到了Google的成功案例,以及适用于千万级别PV站和亿级PV网站的架构层次。 ... [详细]
  • 上图是InnoDB存储引擎的结构。1、缓冲池InnoDB存储引擎是基于磁盘存储的,并将其中的记录按照页的方式进行管理。因此可以看作是基于磁盘的数据库系统。在数据库系统中,由于CPU速度 ... [详细]
  • Centos下安装memcached+memcached教程
    本文介绍了在Centos下安装memcached和使用memcached的教程,详细解释了memcached的工作原理,包括缓存数据和对象、减少数据库读取次数、提高网站速度等。同时,还对memcached的快速和高效率进行了解释,与传统的文件型数据库相比,memcached作为一个内存型数据库,具有更高的读取速度。 ... [详细]
author-avatar
zc43pml
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有