**1.前言**这是我第一次在社区发文章。作为一个大学没毕业的前端菜鸟,平时经常逛各种技术社区。我很高兴发表我的处女作。最近在帮学校开发一个基于微信小程序的投票系统项目,在开发中遇到了很多坑,也有一些心得,所以想分享给大家,共同探讨,共同进步。(个人开发技术有限,不好勿喷--)。2.功能需求方案可发布各类主题活动进行投票。各种主题活动可以支持作品展示和参与投票活动。进入微信小程序后,用户无需登录即可直接投票,每个用户每天只能为同一个作品投票一次,第二天可以继续投票。显示截止投票时间,通过倒计时显示。每件作品自动生成一个二维码,扫描二维码可进入作品投票介绍界面。其他:作品筛选、作品搜索、作品排名等。3、开发环境及工具服务器环境:Ubuntu16.04+Node.js+Express数据库环境:MySQL前端及大众测试:微信小程序开发工具技术:Javascript+HTML+CSS+Node4.效果展示首页筛选搜索详情页排行的界面就不展示了,因为还在测试阶段,界面还是比较学院派,以后会增加功能和界面稍后修改。5.实现过程及难点总结(代码)其实整个项目的难点并不多,大部分都是数据展示和一些简单的交互。要打造一个比较完善的投票系统,关键点一定是能否将投票功能完美的实现并展现在用户面前。本项目涉及的难点在于如何让用户无需注册登录,甚至无需获取微信登录权限即可投票。同时,系统可以准确记录每个用户的投票行为。这里我们将讨论数据库。Node.js的设计、小程序登录机制及应用。在数据库设计中,由于每个用户每天只能给一个作品投票,所以有三种可能的解决方案:1.每个用户都有一个对应的投票表,每投一个作品,就会增加该作品的投票数.id,第二天删除id,不存在再投票。2.同理,每一个作品都可以有一个对应的投票表,一个用户投一票,用户的id会被加进去。3.在工作表中添加投票用户字段,如果有用户投票,则将用户的id添加进去,判断id是否存在,判断是否已经投票。前两种方案会在无形中生成很多表,而实际上,这些表其实是同一种性质的。所以最终选择了第三种方案,在工作表中增加一个字段,在该字段中加入每个投票用户的id(如果用户数量较多,应该使用之前的或者其他更好的方案)。但是一般字段使用的varchar类型的最大长度只有255,不能满足数据较多时的需要。Mysql的文本类型可以满足,最大的LONGTEXT可以有4GB的存储空间,足够一个校园的用户数量(比如一个用户的openid有28个英文字符,也可以存储几千万用户.不过据说text类型的性能不如varchar等类型,至于影响有多大,我没测试过)。但是在同一个字段中添加字符需要做一些处理,将添加的数据用符号分隔,方便后续查询。获取小程序的用户id那么如何识别每个投票用户的身份呢?如果您无权获取微信用户信息,您可以直接获取微信用户的openid,该用户的openid是用户的唯一标识。官方对小程序的介绍是:小程序可以通过微信提供的官方登录能力轻松获取微信提供的用户身份,快速建立小程序内的用户体系。小程序的API中有一个wx.login方法,提供了小程序的Appid和AppSecret以及每次登录生成不同的用户登录凭证,然后通过微信官方接口获取用户的openid等数据服务器端。具体官方文档和API链接:https://developers.weixin.qq...微信请求:wx.login({success:res=>{console.log(res.code)wx.request({url:'http://localhost:8080/data',data:{code:res.code,Appid:"wxXXX",AppSecret:"XXX",},header:{'content-type':'application/json'},成功:function(next){console.log(next.data)that.setData({showlist:next.data})}})}});服务器端获取openid(Node)//定义微信小程序向服务器发送参数varcode=req.query.code;varappid=req.query.Appid;varappsecret=req.query.AppSecret;varindex=req.query.id;console.log(appid);//请求外部url,传参返回用户ID等数据request('https://api.weixin.qq.com/sns/jscode2session?appid='+appid+'&secret='+appsecret+'&js_code='+code+'&grant_type=authorization_code',function(error,response,data){if(!error&&res.statusCode==200){constconnection=mysql.createConnection({//连接数据库配置信息host:"localhost",user:"root",password:"XXX",port:3306,database:"display",multipleStatements:真的});//打开链接connection.connect();//将返回的数据字符串转换成JSON格式。varid=JSON.parse(data)varnewid=id.openid}})将用户插入到数据库中openid然后将用户id添加到数据库中的相应字段即可,不过这里有两个细节,也可以说是两个坑。由于我自己的厨艺,弄了好久才搞定。。。1.如果用户还没有投票vote,那么在字段中加入用户的openid,如果用户投票过,则用户id已经存在于字段,并返回提示信息。文本类型没有默认值,所以当最初没有投票用户时它是空的。这里我直接使用JS的indexOf函数来查询node中是否包含id字符串,所以一旦该字段为Null,查询就会报错。解决方法:查询前,先将所有为Null的字段转为空字符串。一开始想在操作前先用JS判断字段是否为空,后来想到更好的解决办法是直接用update把字段的null值改成空字符串再查询,这样就多了清爽不如用JS判断。connection.query("updatedisplaysetd_user=''whered_userisnull",[],function(queError,queData){......})2、插入用户id数据时,使用","设置每个用户的openid是分开的,用concat函数拼接字符串。但是,由于前面获取到的id变量和一个字符串“,”拼接在一起,所以写法还是比较棘手的。concat的第二个参数是一个字符串,用引号""括起来。天真地以为变量直接写在里面,外面有括号,出来就直接是字符串了?但是会报错,显示的不是字符串。解决方法:如果用ES6语法可以直接写`${newid}`,就得这样写:connection.query("updatedisplaysetd_user=concat(d_user,"+`'${newid},'`+")whered_id="+index,[],function(err,data){console.log(err)//nullconsole.log(data)//object});解决了这两个问题后,另一个是同时增加票数和其他代码,这里不再赘述。定时清除用户id是让用户每天都可以投票的关键。在指定时间清空字段中的openid信息,可以实现用户第二天可以继续投票的功能。有很多方法可以实现这一点。第一种是直接在数据库层进行操作,通过存储过程或者代码,将字段的内容赋值为空值。第二种是在Node中使用定时器或者其他方法在指定的时间重新赋值数据库中字段的内容。我用一个JS定时器来解决,每天00:00:00重新分配。但是要注意timer的start和clear,不然一直开肯定对性能有影响。vartimer=setInterval(function(){vardate=newDate();varhours=newDate().getHours();varminutes=newDate().getMinutes();varseconds=newDate().getSeconds();if(hours==23&&minutes==59&&seconds==59){connection.query("updatedisplaysetd_user=''",[],function(err,data){console.log(data)})}},1000)6.后期更新后有时间更新活动倒计时的写法,每页二维码的生成方法等7.总结由于数据库不是很好,肯定有很多不合理的地方,希望得到大佬们的指导。同时,小程序前端还有很多坑,后面会单独写一篇文章来分享。如果大家觉得还有点意思,希望大家给我点个赞什么的,给菜鸟们一些鼓励哈哈哈哈。
