电影投票系统

Java课程设计,想试试前后端完全分离的开发(原来在Class+时曾体验过),于是有了下面4天2人的开发历程。先上图吧!Github地址:https://github.com/ycjcl868/VoteApp,Demo:http://movie.ycjcl.cc

前台投票页:

  • 查看电影列表
  • 执行投票操作
  • 查看一小时内的日志及日志数
  • 数据统计图
  • 搜索
  • 投票成功分享

后台管理:

  • 新增电影
  • 删除电影
  • 查看日志
  • 修改电影
  • 查看统计图

系统架构

概述

共用了两台腾讯云服务器(CentOS 7),一台前端Node服务器和一台Java SpringMVC服务器,之前的交互通过JSON。通过前后分离,将MVC中的ViewController层分给前端,后台SpringMVC负责Model层,只提供JSON数据,交互如图:

看到这个架构,想起原来大一在Class+的困惑,问了孵化器里的很多人,都不能解决我的问题。我的问题是这样的,Class+的App和后台(也是Spring,JSON接口)是写好的,当时只会PHPNode没这么流行。然后要做一个网站,接口要调用Spring写好的,然后把整个前端静态页面管理组织起来。当时的PHP就相当于现在的Node,只不过那时候的纯PHPPOST请求时真是麻烦(调用CURL一堆方法)。且那时候傻到直接将Java后台地址调到$.ajax(url)里,导致跨域问题,用JSONP,还让写后台Spring的越越修改Access-Control头,且返回的JSON数据有时还需要用‘(‘+eval(str)+’)’去处理一下。现在好了,直接Node前后一体化JS代码解决疑惑。

前端服务器

前端在数据层采用Express+Vue,UI 层前台使用腾讯手 Q的Frozenui + Zepto + LayerMobile + CanvasJS(这个我极力推荐,个人贡献了中文文档),后台管理使用老油条组合 jQuery + BootStrap 。 整个前端使用Gulp进行自动化处理,配置见Express+Gulp配置高效率开发环境

首页:

日志页:

数据统计页:

后台页面

信息安全

对传输数据进行了加密处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
* 执行投票操作(POST)
* @param userIP 用户ip
* @param token 用户唯一标识加密(ip+'xxxx').md5()
* @param cineId 电影id
* @param province 省份
*
* 返回:state // 状态或票数
* cineId // 电影id
*/
router.post('/doVote', function(req, res, next) {
var params = {};
var send = res;
params.userIP = req.session.ip;
params.token = api.cryptoToken(req.session.ip);
params.cineId = req.body.cineId;
// 通过百度接口用 ip 获得省份
api.getProvince(req.session.ip,function (res) {
params.province = res;
console.log(params);

// 执行投票操作
api.doVote(params,function (res) {
console.log(res);
send.send(res);
})
});
});

然后后台Java拿到ip后,对ip进行加密然后判断是否等于前端传来的token来执行投票操作。

本地存储

首次在项目中使用localStorage的新特性,存储了是否投过票voteId和投票时间voteTime。来前端控制一个小时内只能投票一次(当然后台 Java 也得控制呢~)。当Vueready生命周期时就判断:

1
2
3
4
5
6
7
8
9
var currentTime = new Date().getTime();
var voteTime = localStorage.getItem('voteTime');
// console.log('currentTime'+currentTime);
// console.log('voteTime'+voteTime);
// console.log(currentTime - voteTime >= 3600000);
if(currentTime - voteTime >= 3600000){
// 一个小时后,就可以投票了(实际上是可以向 Java 发请求了)
localStorage.setItem('voteId','-1');
}

这样,再次刷新时,如果投过button就成灰色,效果如图

当然,另一舍友今天也问我,为什么不用cookiecookie还可以设置过期时间呢,区别是什么?,见文解析详说 Cookie, LocalStorage 与 SessionStorage。不过,我认为cookie也是可以的,localStorage是键值对,而cookie只是字符串,没有封装cookie方法时操作cookie就比较麻烦。

前端自动化工具Gulp

本想试下Webpack,发现不好配,还是配下稍微熟悉点的Gulp,发现真是方便,自动编译Less,自动检查语法错误,自动压缩,自动浏览器刷新,前端开发神器。

NodeJS图片异步上传

这一块原来用Express框架一直没上传过,这次看了multer官方原版文档 + 原来前端原生JS使用的Formdata对象,完美实现异步上传预览。 下次发博时写个详细的解决Express异步上传图片预览(因为现在用国内搜索引擎搜出来的基本都用不了,不是让你用jquery插件,就是让你npm install xxx模块,都不能很好的解决。)

后台服务器

只负责提供JSON数据,基本架构Springmvc+Spring+MyBatis是我舍友写的。数据库采用 Mysql(本来打算用Oracle,不过实在是太重了,不易管理,所以换Mysql了)

遇到的问题

1. 首次和舍友采用前后分离的架构,没有文档驱动,接口就基本上通过 QQ 沟通。因为接口较少。
2. 后台英文要稍微好点,不然{“statue”:1}{“status”:1}是很容易写错了。(自我反省了好久,我有没有错,才发现不是我的错。)

3. json问题,有时一粗心,就忘通过JSON.parse(jsonStr)json字符串转成json对象了。
4. 前端完全分离的调试问题,舍友的电脑能连的Wifi我连不上,我能连的他连不上。然后就买了腾讯云的CentOS 7 Java服务器。
5. 舍友对Linux不是太了解,在大小写方面目录权限问题上没处理好!

6. 后台对编码的处理没统一,先传过去的中文全是乱码,我一看数据库格式不是utf8_general_ci就明白了,结果还是乱码,舍友一看肯定是SpringMVC没有设置过滤器UTF-8格式,一加就OK
7. 部署在云上时才发现的,因为用了Nginx服务器代理到了NodeJS,所以才开始获取到的用户ip全是127.0.0.1,最后Node要获取ip的话,只能通过X-Forwarded-For 的头(起初我个人觉得不太安全,不过一测试,结果不能伪造)

8. 正式投票时,发现投了6个左右,后台Java Spring后台就挂掉了,显示的错误信息大概的意思是阻止请求信息,一查发现是没有配置连接数,所以就爆掉了,临时写了一个反馈的弹窗。最后改了之后,就能解决小量高并发了。