基于nodejs的问卷调查系统

2016-12-28 04:23:09

花了4天时间撸了一个问卷调查系统,算是入门nodejs后端开发。

github传送门:https://github.com/flute/survey

技术

  • 后端:nodejs+express+mysql
  • 前端:material design

install

  1. npm install
  2. 配置数据库 conf/db.js ,导入sql文件 mysql.sql
  3. node app.js

功能

  1. 登陆验证
  2. 问题类型包括 单选、多选及问答三类
  3. 查看问卷列表、删除
  4. 填写提交问卷
  5. 问卷结果列表及结果详情

注:

在系统实现过程中,数据表的设计及数据操作有些麻烦,感兴趣的往下看:

为了问卷结果的可读性及统计方便,数据表设计时将 问卷、问题、选项 分为三个表,在插入、读取问卷时,需要顺序、批量进行数据库操作。

如:新增1个问卷,该问卷有10个问题,单选及多选问题包含2个以上的选项。

那么数据操作顺序是:

  1. 先插入问卷,并得到返回的问卷ID。
  2. 得到问卷ID,按顺序插入10个问题,每个问题在插入成功后,返回问题ID。
  3. 每个问题插入成功时得到问题ID,按顺序插入该问题的多个选项,只有当该问题及问题选项全部插入成功时,开始执行下个问题。

可以看到3是2中的内部循环,2本身是个循环,1和2是顺序执行关系。对于这样的数据插入,如果用常规的嵌套回调,光一个问题就是三层以上的嵌套,几十个问题的话就没法玩了。而且所有的操作只需要一个返回结果,及最终成功与否,只要当其中任何一次插入失败则失败。

最终实现方法是使用async.eachSeries,以下代码实现上述问题:

insertSurvey: function (data,callback) {
	//从mysql连接池获取连接
	pool.getConnection(function(err,connection){
		if( err ){
			callback(err);
			return;
		}
		connection.query( "insert into t_survey(... , ... ,...) values(..., ...)", function(err,res){
			if(res){
				//问卷插入成功
				var surveyId = res.insertId;
				//异步批量按序插入问题
				//拼接sql数组
				{...}
				/**
				 * insertQuestionSql 是插入问题的语句数组
				 * 
				 * insertQuestionSql = [
				 * 		insert into t_survey_question(createAt,type,.....) values(... ,.. , ...),
				 * 		insert into t_survey_question(createAt,type,.....) values(... ,.. , ...),
				 * 		.....
				 * ];
				 */
				async.eachSeries( insertQuestionSql, function(item,questioncb){
					connection.query( item.survey, function(err, results) {
						if(err) {
							questioncb(err,result);
						}else{
							//问题插入成功,继续插入选项
							var questionId = results.insertId;
							//如果是单选或多选,存在多个选项,异步批量按序插入选项
							//拼接sql数组
							{...}
							/**
							 * insertOptionSql 是需要插入的选项数组
							 * 
							 * insertOptionSql = [
							 * 		insert into t_survey_option(createAt,type,.....) values(... ,.. , ...),
							 * 		insert into t_survey_option(createAt,type,.....) values(... ,.. , ...),
							 * 		.....
							 * ];
							 */
							if( item.data.type == 'radio' || item.data.type == 'checkbox' ){
								async.eachSeries( insertOptionSql, function( optionitem, optioncb ){
									connection.query( optionitem, function( operror,opresult){
										if(operror){
											optioncb(operror,opresult);
										}else{
											//选项插入成功
											optioncb( opresult.insertId );
										}
									});
								},function(err){
									//当前问题的所有选项插入结束
									if(err){
										callback(err);
									}else{
										callback();
									}
								});
							}else{
								//问答无选项,直接回调
								questioncb();
							}
						}
					});
				},function(err) {
					//所有问题插入结束
					callback(err);
				});
			}else if(err){
				callback(err)
			}
			//回调结果
			callback(result);
			//释放连接 
            connection.release();
		})
	})
},

最终的解决方案也是三层嵌套回调,也对应了对三个表的操作,暂时算是最优解决方案了。

async.eachSeries 保证了SQL的执行顺序,而且当其中一条执行异常,就不会继续执行下一条,简单示例:

var sqls = [
  "INSERT INTO log SET data='data1'",
  "INSERT INTO log SET data='data2'",
  "INSERT INTO log SET data='data3'"
];

async.eachSeries(sqls, function(item, callback) {
  // 遍历每条SQL并执行
  connection.query(item, function(err, results) {
    if(err) {
      // 异常后调用callback并传入err
      callback(err);
    } else {
      console.log(item + "执行成功");
      // 执行完成后也要调用callback,不需要参数
      callback();
    }
  });
}, function(err) {
  // 所有SQL执行完成后回调
  if(err) {
    console.log(err);
  } else {
    console.log("SQL全部执行成功");
  }
});
Echarts3 中国地图下钻至县级

Echarts3 地图下钻至县级 看了会D3.js,鉴于学习曲线较高,且要实现的效果不复杂,遂使用Echarts完成——中国地图下钻至县级。 HTML <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>echarts3中国地图下钻至县级</title> <link rel="stylesheet" type="text/css" href="static/css/main.css&

2016总结

2016 过去的这一年,算是一个转折点吧,学生时代的终结,开始工作了。毕业后的几个月,也会经常想起上学时的很多美好,日常用语也多了句“我在学校的时候...”,我想所有刚离校的同学有共感,毕竟伴随了16年的读书模式要转换了,虽然在学校时也会出去做外包,去实习,但当全职工作后还是很回念学生时代。 说是16年的年度总结,其实多半是下半年的一些变化。以前我觉得总结什么的,都是给别人看的,形式主义。但工作的半年我转变了自己的看法,我尝试在工作的每周、每月梳理下,在每个时间段内,自己学到的新东西以及欠缺的东西,这样就有一种看着自己不断成长的感觉。不然你可能只是觉得自己好像增长了,好像有些问题被人诟病,但有不明确的知道哪些点增长了,哪些还在拖后腿。 既然是贴着程序猿的标签,那年度总结就分为生活和技术两部分吧: 生活 虽然学的是自动化专业,但是转战互联网其实从大二就开始了,虽然家里人都希望去稳定的国企,但他们也尊重我的选择,所以毕业后之久投身IT行业有惊无险。前半年的毕业找工作期也是经历了很多波折,换了好几个offer。。虽然一波三折,但是吃一堑长一智,记得任何时候都有必要签书面合同!!!不要因为对方是熟人而口头承诺!!!这是对自己的基本保障。 get 自己理发技能,从6月份开始远离理发店,到目前已经半年时间自行理发了,虽然插曲不断,总归做了件自己一直想做的事~