7_1_Redis实现赞踩功能

一、实现需求

1. 登录账号以后,在首页home.html内可以点赞或者取消赞,只能点赞一次,点赞以后就不可再点赞;

   取消赞以后为0.

2 点开news以后也可以点赞或者取消赞。

二.具体实现

1  util包下写一个类似DAO的组件,组件类包括Jedis初始化,获取Jedis,Jedis的获取get,set,获取集合大小等操作。

package com.nowcoder.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**
 * Created by Administrator on 2017/5/1.
 */
@Service
public class JedisAdapter implements InitializingBean {

    private static final Logger logger = LoggerFactory.getLogger(JedisAdapter.class);

    private Jedis jedis = null;
    private JedisPool jedisPool = null;

    @Override
    public void afterPropertiesSet() throws Exception {
        //初始化
        jedisPool = new JedisPool("localhost", 6379);
    }

    //获取一个Jedis
    private Jedis getJedis(){
        try{
            jedis =  jedisPool.getResource();
        }catch (Exception e){
            logger.error("获取jedis失败!" + e.getMessage());
        }finally {
            if(jedis != null){
                jedis.close();
            }
        }
        return jedis;
    }

    /**
     * 获取Redis中集合中某个key值
     * @param key
     * @return
     */
    public String get(String key){
        Jedis jedis = null;
        try {
            jedis =  jedisPool.getResource();
            return jedis.get(key);
        }catch (Exception e){
            logger.error("Jedis get发生异常 " + e.getMessage());
            return null;
        }finally {
            if(jedis != null){
                jedis.close();
            }
        }
    }

    /**
     * 给Redis中Set集合中某个key值设值
     * @param key
     * @param value
     */
    public void set(String key, String value){
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            jedis.set(key, value);
        }catch (Exception e){
            logger.error("Jedis set 异常" + e.getMessage());
        }finally {
            if(jedis != null){
                jedis.close();
            }
        }
    }

    /**
     * 向Redis中Set集合添加值:点赞
     * @return
     */
    public long sadd(String key, String value){
        Jedis jedis = null;
        try{
            jedis =  jedisPool.getResource();
            return jedis.sadd(key, value);
        }catch (Exception e){
            logger.error("Jedis sadd 异常 :" + e.getMessage());
            return 0;
        }finally {
            if (jedis != null){
                jedis.close();
            }
        }
    }

    /**
     * 移除:取消点赞
     * @param key
     * @param value
     * @return
     */
    public long srem(String key, String value){
        Jedis jedis = null;
        try{
            jedis =  jedisPool.getResource();
            return jedis.srem(key, value);
        }catch (Exception e){
            logger.error("Jedis srem 异常:" + e.getMessage());
            return 0;
        }finally {
            if (jedis != null){
                jedis.close();
            }
        }
    }

    /**
     *p判断key,value是否是集合中值
     * @param key
     * @param value
     * @return
     */
    public boolean sismember(String key, String value){
        Jedis jedis = null;
        try{
            jedis =  jedisPool.getResource();
            return jedis.sismember(key, value);
        }catch (Exception e){
            logger.error("Jedis sismember 异常:" + e.getMessage());
            return false;
        }finally {
            if (jedis != null){
                try{
                    jedis.close();
                }catch (Exception e){
                    logger.error("Jedis关闭异常" + e.getMessage());
                }
            }
        }
    }

    /**
     * 获取集合大小
     * @param key
     * @return
     */
    public long scard(String key){
        Jedis jedis = null;
        try{
            jedis =  jedisPool.getResource();
            return jedis.scard(key);
        }catch (Exception e){
            logger.error("Jedis scard 异常:" + e.getMessage());
            return 0;
        }finally {
            if (jedis != null){
                jedis.close();
            }
        }
    }

}

2 util包下写一个util工具类,实现点赞生成键key的值。

package com.nowcoder.util;

import org.springframework.stereotype.Service;

/**
 * Created by Administrator on 2017/5/1.
 */
public class RedisKeyUtil {

    private static String SPLIT = ":";
    private static String BIZ_LIKE = "LIKE";
    private static String BIZ_DISLIKE = "DISLIKE";

    /**
     * 产生key:如在newsId为2上的咨询点赞后会产生key: LIKE:ENTITY_NEWS:2
     * @param entityId
     * @param entityType
     * @return
     */
    public static String getLikeKey(int entityId, int entityType){
        return BIZ_LIKE + SPLIT + String.valueOf(entityType) + SPLIT + String.valueOf(entityId);
    }
    /**
     * 取消赞:如在newsId为2上的资讯取消点赞后会产生key: DISLIKE:ENTITY_NEWS:2
     * @param entityId
     * @param entityType
     * @return
     */
    public static String getDisLikeKey(int entityId, int entityType){
        return BIZ_DISLIKE + SPLIT + String.valueOf(entityType) + SPLIT + String.valueOf(entityId);
    }

}

3 Service包下写上一个判断点赞还是反对的方法,当点赞后将当前点赞用户id存入likeKey集合中,同时从disLikeKey中移除此id:

package com.nowcoder.service;

import com.nowcoder.util.JedisAdapter;
import com.nowcoder.util.RedisKeyUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * Created by Administrator on 2017/5/1.
 */
@Service
public class LikeService {

    @Autowired
    JedisAdapter jedisAdapter;

    /**
     * 判断是点赞还是点反对
     * @param userId
     * @param entityType
     * @param entityId
     * @return
     */
    public int getLikeStatus(int userId, int entityType, int entityId) {
        //根据当前用户的userid分别生成一个likeKey 和 disLikeKey,再分别判断这两个值是否在对应的Like集合中和disLikeKey集合中
        //比如如果在likeKey集合中,就返回一个1,否则返回-1
        String likeKey = RedisKeyUtil.getLikeKey(entityId, entityType);
        //判断值为userId 的用户是否在key为listKey 的集合中
        if(jedisAdapter.sismember(likeKey, String.valueOf(userId))){
            return 1;
        }
        String disLikeKey = RedisKeyUtil.getDisLikeKey(entityId, entityType);
        return jedisAdapter.sismember(disLikeKey, String.valueOf(userId)) ? -1: 0;
    }

    /**
     * 点赞:即当前用户点赞后,被点赞用户的like集合中就会加上一个该点赞的用户信息
     * @param userId
     * @param entityType
     * @param entityId
     * @return
     */
    public long like(int userId, int entityType, int entityId){
        //在当前news上点赞后获取key:   LIKE:ENTITY_NEWS:2
       String likeKey = RedisKeyUtil.getLikeKey(entityId, entityType);
       //在喜欢集合中添加当前操作用户的userId(即当前用户点赞后,被点赞用户的like集合中就会加上一个点赞的用户信息)
       jedisAdapter.sadd(likeKey, String.valueOf(userId));

       String disLikeKey = RedisKeyUtil.getDisLikeKey(entityId, entityType);
       jedisAdapter.srem(disLikeKey, String.valueOf(userId));

       //返回点赞数量
        return jedisAdapter.scard(likeKey);
    }

    /**
     * 反对 :即当前用户点反对后,被点反对用户的like集合中就会加上一个该点反对的用户信息
     * @param userId
     * @param entityType
     * @param entityId
     * @return
     */
    public long disLike(int userId, int entityType, int entityId){

        //谁点击反对,谁就出现在key为dislikeKey的Set集合中
        String disLikeKey = RedisKeyUtil.getDisLikeKey(entityId, entityType);
        jedisAdapter.sadd(disLikeKey, String.valueOf(userId));

        //从赞中删除
        String likeKey = RedisKeyUtil.getLikeKey(entityId, entityType);
        jedisAdapter.srem(likeKey, String.valueOf(userId));

        return jedisAdapter.scard(likeKey);
    }

}

4 Controller: 调用LikeService,将当前用户id存入Redis的LikeKey集合中,并更新News表中 的like_count数量;对应的dislike也是一样。

package com.nowcoder.controller;

import com.nowcoder.model.EntityType;
import com.nowcoder.model.HostHolder;
import com.nowcoder.model.News;
import com.nowcoder.service.LikeService;
import com.nowcoder.service.NewsService;
import com.nowcoder.util.ToutiaoUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * Created by Administrator on 2017/5/1.
 */
@Controller
public class LikeController {

    @Autowired
    LikeService likeService;
    @Autowired
    NewsService newsService;
    @Autowired
    HostHolder hostHolder;

    @RequestMapping(path = {"/like"}, method = {RequestMethod.GET, RequestMethod.POST})
    @ResponseBody
    public String like(@RequestParam("newsId") int newsId){
        //在newsId 的资讯上加入当前用户
        long likeCount = likeService.like(hostHolder.getUser().getId(), EntityType.ENTITY_NEWS, newsId);

        //更新点赞数
        //News news = newsService.getById(newsId);
        newsService.updateLikeCount(newsId, (int)likeCount);

        return ToutiaoUtil.getJSONString(0, String.valueOf(likeCount));
    }

    @RequestMapping(path = {"/dislike"}, method = {RequestMethod.POST, RequestMethod.GET})
    @ResponseBody
    public String disLike(@RequestParam("newsId") int newsId){

        //点击反对:调用disLike,将当前点击反对的用户id从key为dislikeKey的集合中移除
        long likeCount = likeService.disLike(hostHolder.getUser().getId(), EntityType.ENTITY_NEWS, newsId);
        if(likeCount <= 0){
            likeCount = 0;
        }

        //更新喜欢数
        newsService.updateLikeCount(newsId, (int)likeCount);
        return ToutiaoUtil.getJSONString(0, String.valueOf(likeCount));
    }

}

5. NewsService:

  public int updateLikeCount(int newsId, int likeCount){
        return newsDao.updateLikeCount(newsId, likeCount);
    }

NewsDao:

   @Update({"update", TABLE_NAME, "set like_count=#{likeCount} where id=#{newsId}"})
    int updateLikeCount(@Param("newsId") int newsId, @Param("likeCount") int likeCount);

6. 同时HomeController中首页获取News上的点赞时,要加入判断。如果是未登录,点赞数全部为0;登录后就获取点赞的状态判断是点赞还是反对。

 if (localUserId != 0) {
                vo.set("like", likeService.getLikeStatus(localUserId, EntityType.ENTITY_NEWS, news.getId()));
            } else {
                vo.set("like", 0);
            }

7. NewsController中的获取News详情页也要加入这样的判断:

时间: 2025-01-05 05:42:53

7_1_Redis实现赞踩功能的相关文章

jquery+php实现赞,踩功能

实现赞,踩功能需要的一些需求: 1.记录用户的IP,根据IP判断用户的投票行为是否有效 2.需要两张表,一张是统计赞和踩的数量的,一张是记录赞或踩过的用户IP的 3.页面加载完成需要显示的赞和踩的数据用ajax从服务端获取,以后每次点赞,点踩也是用ajax从服务端获取 html 代码 (额,因为这个主要实现的是逻辑,所以界面就很简单啦 ,嘿嘿) 这个html代码很简单,就不多说了 <body> <p > <input type="button" value

添加顶踩功能

phpcms如何添加顶踩功能步骤: 1.在后台模型增加两个字段,一个goodpost,一个badpost;这个步骤简单,按后台新增加字段下一步就行了. 2.在模块/phpcms/modules/content/增加扩展函数newindex.php,代码如下: <?php defined('IN_PHPCMS') or exit('No permission resources.'); class newindex{ function __construct(){ $this->db=pc_ba

MVC+WCF实现视频播放的顶和踩功能

大家都知道做视频网站必须要有顶和踩的功能,我们的校园视频管理系统的顶和踩做到了和优酷顶和踩一样的效 果,下面我们就介绍一下我做的顶和踩的功能实现. 之前想的是点击图片按钮,直接让显示和数据库中的数据都+1就可以了,后来参照了优酷,决定实现图片的"点 亮"效果,于是将原来的两张带颜色的按钮另做的两张灰色按钮,实现了图片点亮和数据及时更新的效果. ------------------------------------------------------------------------

laravel 记录一次赞 与 取消赞 的功能开发

<p> @if(!$post->agree(Auth::id())->exists()) <a href="{{route('user.post.agree',['id'=>$post->id])}}" class="btn btn-info">赞</a> @else <a href="{{route('user.post.unAgree',['id'=>$post->id])}

2018最新Java实战开发今日头条资讯网站

==================课程目录=====================第1节 开发工具和Java语言介绍主要介绍项目所需要的开发工具,并且会简单回顾这个项目所用到的语言-java,语法基础,控制流,数据结构,面向对象,异常,随机数等. 第2节 Spring入门和模板语法主要结合Spring进行入门介绍,包括参数解析,HTTP Method,AOP等等. 第3节 数据库交互iBatis集成 主要对业务的字段进行设计,数据库的创建,数据库的交互等,并会介绍注解和XML定义以及首页的开

PHP+MySql+jQuery实现的“顶”和“踩”投票功能

index.html <!DOCTYPE HTML><html><head><meta charset="utf-8"><title>演示:PHP+jQuery+MySql实现的"顶"和"踩"功能</title><meta name="keywords" content="PHP,mysql,jquery" /><me

微赞开发有感

微赞的功能很棒,但是看了部分源码后,发现一些问题. 先说下目录结构 http://域名/app/index.php?i=7&c=entry&m=ewei_shopv2&do=mobile&r=goods.detail&id=148&mid=388&from=groupmessage 如上 app表示是根目录下的app目录,这里的东西大多是和手机端有关 i=7应该是表示第7个公众号 c=entry表示要加载东西了. defined('IN_IA') o

微赞WZ安装笔记

微赞官网地址:http://www.012wz.com/ 了解微赞: 微赞程序的介绍: 微赞WZ微信公众平台开源程序-是微动力程序的衍生强化版,基于目前最流行的WEB2.0的架构(php+mysql),实现多微站,多客户转接,多功能群发,粉丝会员积分统一,模块嫁接等功能,具有高度的安全特性!100%开源,程序可自由控制!便于二次开发的开源微信公众平台管理系统!多用户微信公众平台管理系统可简单的实现管理员与各个用户间的授权与管理!已强化了功能模块的管理与应用,方便微信功能独立开发. 选择微赞的几个

chrome模拟手机功能

在搭建好web側环境之后.能够使用chrome来模拟手机的功能 直接上图吧: 图1是直接模拟一个通用的界面 图2里面能够选择不同的手机型号,还是比較全的! 选择一个查看一下,和手机是一样的效果,非常赞的功能!