7_1_Redis实现赞踩功能
Posted noaman_wgs
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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详情页也要加入这样的判断:
以上是关于7_1_Redis实现赞踩功能的主要内容,如果未能解决你的问题,请参考以下文章
Redis_12_Redis集群实现Sentinel哨兵应对高可用