原创文章,转载请注明出处https://blog.csdn.net/qq_41969845/article/details/108406059

一、前言

本文以投票功能为例,从实际例子中熟练掌握redis的应用。阅读本文需要有一定的Java基础和对redis数据结构的了解,如果Java不太行的同学建议关注文章末尾的公众号,对redis数据结构不太了解的同学可以回看我的上一篇文章:详谈redis数据结构

二、投票功能的业务逻辑

大家肯定在大学时期经常在班级QQ群内遇到一些投票的活动。显而易见,投票是一个逻辑很清晰的功能,首先,投票发起人发起投票,然后各位用户可以进行投票,在本案例中票种分为“赞成票”(approval)和“反对票”(against)。以下是每一次投票活动的数据结构:

字段名 对应信息
title 投票活动的标题
content 投票活动的内容
postTime 投票活动的发布时间
approval 支持票数
against 反对票数

那么在这里有几个问题需要读者思考一下:
1、如何避免同一个人既投反对票又投赞成票
2、如何避免同一个人多次投赞成票或反对票
3、如何避免投票者选投不存在的活动
4、如何记录哪位投票者为哪个活动投了何种票
~~~~~~~~~~~~~~~~~~~~~~~~~
先思考一下然后继续往下读吧~~

三、具体实现步骤

具体实现的部分将以各自的功能函数来进行讲解,每一个功能都对应着一个功能函数,或调用其他函数。

3.1、发起投票 initiateVote

3.1.1 、投票活动名

首先,每个投票活动要有一个自己的投票活动名,这里使用"activity:"+activityId进行拼接,其中activityId使用redis中的字符串类型,可以进行自增操作,因此每次发起一个新的投票活动,都会有不同的投票活动名。

//生成一个投票活动的ID,自增String activityId = String.valueOf(conn.incr("activityId:"));String activity = "activity:" + activityId;
3.1.2 、保存投票活动名

为了后续方便查看我们发起了哪些投票活动,也为了方便判断哪些投票活动存在以决定让不让投票者对该未知存在的活动进行投票,我们需要将投票活动名activity保存起来,存在一个activitySet集合内。

//将活动名存进activityList中conn.sadd("activitySet",activity);
3.1.3 、保存投票活动的相关数据

每一个投票活动都有以下活动数据

字段名 对应信息
title 投票活动的标题
content 投票活动的内容
postTime 投票活动的发布时间
approval 支持票数
against 反对票数

其中title和content是从main()函数中传递过来的,postTime是发起活动时的时间戳,approval和against默认为0,后续随着投票者的票数改变。

// 发布时间long now = System.currentTimeMillis() / 1000;//投票活动的相关数据HashMap<String, String> activityData = new HashMap<>();activityData.put("title", title);activityData.put("content", content);activityData.put("postTime", String.valueOf(now));activityData.put("approval", "0");activityData.put("against", "0");conn.hmset(activity, activityData);

将投票活动的所有信息存入HashMap中,然后利用hmset命令存入activity散列中。最后在initiateVote()的结尾处返回activityId,以便在主函数中使用。

3.1.4 、主函数中发起投票的部分

由上可知,主函数需要给initiateVote()传入conn,title,content。之后initiateVote()函数需要给主函数传回activityId。

String activityId = initiateVote(conn, "投票标题", "投票内容:北京大学是个好大学吗?");//发布投票
System.out.println("发起了一个新的投票活动,活动Id为:" + activityId);

到这里,发起投票活动的功能部分已经实现了,运行程序查看
说明投票活动已经被发起。

3.2 、查看投票活动的数据getActivityData()

上一小节讲到发起投票活动,尽管控制台输出了活动Id,但是活动的标题和活动内容都没有显示出来,活动的赞成票数和反对票数也没有展示出来,因此,我们需要一个可以查看投票活动数据的方法。

 //查看投票活动数据public static void getActivityData(Jedis conn, String activity) {System.out.println("投票活动相关信息如下:");Map<String, String> activityData = conn.hgetAll(activity);for (Map.Entry<String, String> entry : activityData.entrySet()) {System.out.println("  " + entry.getKey() + " : " + entry.getValue());}}

使用hgetall命令取出activity散列中所有activity数据存于map中,然后利用entrySet遍历map取出所有键值对。
在主函数中修改代码,让程序在发起投票活动之后调用一下getActivityData(),运行程序试一下。

控制台输出了我们刚刚创建的Id为3的投票活动信息。

3.3、查看已发起的投票活动

因为投票系统可以允许同时有多个投票活动存在,故而,必须在投票之前让投票者知晓系统中有哪些投票活动以便选择。在发起投票的方法中,我们已经将投票活动名activity存入了activitySet集合中,接下来,我们只需遍历该集合即可知晓已有的投票活动。

//取出所有的activitypublic static void getAllActivity(Jedis conn){System.out.println(conn.smembers("activitySet"));}

这个方法实现起来是很简单的,只需使用SET中的smembers命令,传入set-key即可。接下来运行程序来测试下:

控制台输出了我们此前所发起的三次投票活动。

3.4、判断该投票活动是否存在

上节说到,为了让投票者方便选择投票活动,我们输出了所有投票活动名以供提示,但是这并不能保证程序的健壮性,还是有的投票者会输错投票Id选错活动。为此,我们必须在进行投票之前,对投票者选择的活动进行一个判断,若该活动存在则可进行投票,若该活动不在,则不允许投票。
本质上讲,其实就是判断用户输入的Id对应的活动名是否存在于我们存储活动名的集合中,所以我们应当很自然地想到使用SISMEMBER命令:

 public static boolean exists(Jedis conn, String activity) {//activity存在于activitySetif (conn.sismember("activitySet", activity)) {return true;} else {return false;}}

运行程序,测试下该方法:

测试成功

3.5、选择活动进行投票voting()

前面两小节已经很好的为投票活动做了准备,让投票者可以知晓系统中有哪些投票活动,即便选择错误,我们的程序也会做出提示。那么本小节一共要实现的几个难点就在于:
(1)、防止同一投票者多次参加同一个投票活动
(2)、赞成票和反对票要分开存储
我们解决以上难题的方法就是,使用学号,在每一位投票者投一个活动时,在集合中记录下他的学号,下次再选择该活动时,通过集合查询就可以得知这位投票者已经为该活动投过票。
投票者参加投票时,先输入学号,再选择投票活动,然后选择要投的票种。以下是投票活动的流程图。

//选择活动进行投票public static void voting(Jedis conn, String voter, String activity) {int ticket = 0;System.out.println("你好" + voter + "请选择票种:");System.out.println("按下1:投赞成票");System.out.println("按下2: 投反对票");/*** 分割字符串,取出纯Id部分*/String activityId = activity.substring(activity.indexOf(':') + 1);/***先判断赞成票名单和反对票名单内都没有,则说明具备投票资格* 按1,则在赞成票名单中加上名字,赞成票自增* 按2,则在反对票名单中加上名字,反对票自增**/if (!conn.sismember("approvalVoter:" + activityId, voter) && !conn.sismember("againstVoter:" + activityId, voter)) {Scanner in = new Scanner(System.in);ticket = in.nextInt();switch (ticket) {case 1:conn.hincrBy(activity, "approval", 1);//赞成票+1System.out.println(conn.sadd("approvalVoter:" + activityId, voter));//将投票者Id加入approvalVoter集合中System.out.println(voter + "已为" + activity + "投赞成票");break;case 2:conn.hincrBy(activity, "against", 1);//反对票+1conn.sadd("againstVoter:" + activityId, voter);//将投票者Id加入againstVoter集合中System.out.println(voter + "已为" + activity + "投反对票");break;}} else {System.out.println("你已为本活动投过一次票,不能重复投票");}}

四、整理代码

第三章中已经基本实现了本次投票系统的全部核心功能,是不是很简单?但是如果你一味复制我贴出来的代码你会发现,根本无法运行。是的,整篇文章是按照写代码时的思路来写的,所以并不是像一些教材书籍上面一味地去贴源代码。如果你不幸读到那种书,还是早日放弃吧。源码链接在文章末尾,快去下载下来,再仔细读一遍吧~
那么接下来,为了让我们的程序能有点实用的感觉,我们将在主函数中加上一层循环,方便我们可以一直发号施令。

public static void main(String[] args) {//连接,演示作用,IP地址和端口号请改成自己的Jedis conn = new Jedis("IP地址", 端口号);conn.select(1);//redis有16个数据库,这里选用1号数据库tips();//界面提示int a = 0;String activity = null;//定义activity的键Scanner in = new Scanner(System.in);while ((a = in.nextInt()) != -1) {switch (a) {case 1: //发起一个新的投票活动System.out.println("1#");String activityId = initiateVote(conn, "投票标题", "投票内容:北京大学是个好大学吗?");//发布投票System.out.println("发起了一个新的投票活动,活动Id为:" + activityId);getActivityData(conn, "activity:" + activityId);break;case 2://展示已存在的投票活动System.out.println("2#");getAllActivity(conn);break;case 3://选择活动进行投票System.out.println("3#");System.out.println("请输入你的学号:");String voter = "voter:" + in.nextInt();System.out.println("请输入你要参加的投票活动:");String activityVoting = "activity:" + in.nextInt();if (exists(conn, activityVoting)) {voting(conn, voter, activityVoting);System.out.println("投票结束");} else {System.out.println("不存在该投票活动");}break;case 4://查看投票活动的各种数据System.out.println("4#");System.out.println("请输入你想查看的投票活动Id");activity = "activity:" + in.nextInt();getActivityData(conn, activity);break;default:tips();}}}

其中的tips()函数其实只不过是一些提示性语句,为了防止main函数太过冗长就单独提取出来了。

五、总结

其实以上功能也可以使用关系型数据库来进行实现,对于许多初学者,可能关系型数据库更方便更直观,但是redis的效率是相当高的,我们的投票活动数据访问量微乎其微,暂时看不出来差别,一旦数据量上去了,redis的优势就显而易见了。
本文通过一个简单的投票系统来使用了一下redis的各种数据结构,其实这个系统还有许多可以完善的地方,比如设置一个过期时间,超过这个时间,投票活动的票数就固定下来,不允许再进行投票。再比如,已经为某个活动投了反对票,但是想改为赞成票要怎么实现。一切都有待读者去研究
下面是本次源码的链接:
vote源码下载

对Java系列知识感兴趣的朋友可以加入QQ群
慧梦软件开发技术联盟:952317701
更多系列文章在java高级程序开发微信公众号

redis后台实现投票功能相关推荐

  1. 公众号助手后台怎么设置投票功能?

    大家在运营微信公众号的过程中不知道最关注的问题是什么?可能每个人都有不同的答案,但我觉得如果要找个最通用的可能非"粉丝量"莫属,作为公众号运营者,每天除了不断的编辑图文内容排版外, ...

  2. python公众号投票_如何使用微信公众号后台投票功能?

    大家在运营微信公众号的过程中不知道最关注的问题是什么?可能每个人都有不同的答案,但我觉得如果要找个最通用的可能非"粉丝量"莫属,作为公众号运营者,每天除了不断的编辑图文内容排版外, ...

  3. php+mysql投票代码_PHP+jQuery+MySql实现红蓝投票功能

    本文是一篇综合知识应用类文章,需要您具备PHP.jQuery.MySQL以及html和css方面的基本知识.本文在<PHP+MySql+jQuery实现的"顶"和" ...

  4. PHP+jQuery+MySql实现红蓝投票功能

    这是一个非常实用的投票实例,应用在双方观点对抗投票场景.用户可以选择支持代表自己观点的一方进行投票,本文以红蓝双方投票为例,通过前后台交互,直观展示红蓝双方投票数和所占比例,应用非常广泛. 查看演示 ...

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

    当我们浏览网页时,我们想对网页内容如文章.评论中的观点持赞同或反对意见时,可以通过点击网页中的"顶"和"踩"来进行投票.而整个交互过程,开发者可以通过ajax异 ...

  6. 【SpringBoot项目实战+思维导图】瑞吉外卖①(项目介绍、开发环境搭建、后台登陆/退出功能开发)

    文章目录 软件开发整体介绍 软件开发流程 角色分工 软件环境 瑞吉外卖项目介绍 项目介绍 产品原型 技术选型 功能架构 角色 开发环境搭建 数据库环境搭建 创建数据库 数据库表导入 数据库表介绍 Ma ...

  7. 城乡投票源码php_PHP发表心情投票功能示例(附源码)

    当浏览新闻页面或者其它页面的时候会有阅读后的感受,比如给力.淡定.打酱油.加油.坑爹等等的表情.让读者打分,看看自己的感受是否与其他读者一样.很不错的交互! 立即下载:moodjb51.rar(htt ...

  8. java hincrby_使用Redis构建文章投票网站(Java)

    文章投票网站的redis相关Java实现 需求: 1.要构建一个文章投票网站,文章需要在一天内至少获得200张票,才能优先显示在当天文章列表前列. 2.但是为了避免发布时间较久的文章由于累计的票数较多 ...

  9. 实现一个简单的投票功能

    实现一个简单的投票功能 最近项目中需要用到一个投票功能,当时觉得简单,向都没想就动手开始做,没想到走了不少弯路. 后来才发现,是想的太过简单了.来看看改进后的功能. 第一步:数据库设计 两个表:一个主 ...

最新文章

  1. 算法小论——第三章 又把新桃换旧符
  2. AI算法在FPGA芯片上还有这种操作?| 技术头条
  3. IBM X3650 M2 BR10i卡的阵列配置方法
  4. java 调用启动远程shell脚本,启动spark
  5. 计算机技术在排水领域的应用,浅谈计算机技术在市政给排水中的应用.doc
  6. SVN服务器使用(一)
  7. java测试字符串的编码_Java字符串测验
  8. php preview,preview.php
  9. 小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。
  10. 无法启动此程序,因为计算机中丢失 的解决办法
  11. java运行无法加载主类_java运行显示“找不到或无法加载主类”的解决办法(linux)...
  12. 华为供应链的“危”与“机”
  13. 运动数据采集,医疗数据采集
  14. 斗地主发牌及排序流程
  15. NVIDIA GPU 计算能力
  16. STM32 CANbootloader 升级功能开发(3)逻辑功能开发
  17. 中国教育培训机构市场运营状况与投资咨询预测报告2022年版
  18. python 输出没有逗号的list_阿博Python之路数据类型(下)以及数据类型转换
  19. 在VS2012中添加.NET Framework 4.5.2
  20. VirtualBox扩展包安装教程(保姆级一步到位)

热门文章

  1. 地球引擎初级教程——影像的镶嵌和拼接Mosaics and Composites(含长津湖区域练习)
  2. AMD 和 CMD 的区别有哪些? (玉伯)
  3. error: L6002U: Could not open file .\objects\xxx.o: No such file or directory
  4. 区块链分片技术相关资料收集
  5. 2023年JDK收费临时解决方案
  6. Consider defining a bean of type ‘Mapper‘ in your configuration.
  7. 国产系统中标麒麟neokylin上的视频监控系统
  8. 2021字节跳动春招技术面试题:mysql间隙锁触发条件
  9. wallhaven怎么下原图_从哪里可以获得很高分辨率的大量壁纸图片?
  10. 【数量金额辅助核算的注意事项】