项目记录
Table of Contents
生成Express项目
Node.js的安装在此跳过. 本项目在Node.js的基础上开始.
# 安装express npm install express-generator -g # 查看express命令选项 express -h # 创建项目 express --view=hbs healthy # 安装依赖 cd myapp npm install # 运行 npm start # 或者 DEBUG=healthy:* npm start # Linux, MacOS set DEBUG=healthy:* & npm start # Windows
此时可在浏览器中输入 http://localhost:3000 访问该应用.
目录结构
/bin: 用于应用的启动. /public: 放置静态资源. /routes: 放置路由. /views: 放置模板文件(html). app.js: 程序的入口文件
模板引擎
本项目使用 handlebars
模板引擎, 该模板引擎默认使用的模板文件的后缀名是 hbs
, 因此 views子目录
中的文件全是 hbs
结尾的. 这边我们进行修改, 使模板引擎使用后缀名为 html
的文件作为模板文件.
修改根目录下的 app.js
文件, 加入以下几句话:
// 在开头添加如下代码 var hbs = require('hbs'); // 将 app.set('view engine', 'hbs'); 改成如下代码 app.set('view engine', 'html'); // 紧接上面一句, 添加如下代码 app.engine('html', hbs.__express);
并将 views
目录下的文件后缀名直接改成 html
.
MySQL
以下通过一个简单的例子来说明如何将Express与MySQL整合起来.
创建表
创建一个简单的表, 表结构如下:
MySQL模块
在 package.json
的 dependencies
中新增以下配置:
"mysql":"latest"
执行 npm install
.
目录结构
根据需要的功能, 在根目录再新建三个目录, 分别管理.
mkdir util # 工具 mkdir conf # 配置 mkdir dao # 与数据库交互(Data Access Object)
conf目录
新建配置文件, 编定MySQL数据库连接配置. emacs conf/db.js
:
// MySQL数据库联接配置 module.exports = { mysql: { host: '127.0.0.1', user: 'root', password: '123456', database:'healthy', // 前面建的user表位于这个数据库中 port: 3306 } };
dao目录
该目录下需要新建两个文件. 第一个(userSqlMapping.js)的内容是对数据库中某个表进行操作的SQL语句. 第二个(userDao.js)的内容是获取前端传过来的数据, 通过SQL语句存到MySQL中.
emacs dao/userSqlMapping.js
:
// CRUD SQL语句 var user = { insert:'INSERT INTO user(id, name, age) VALUES(0,?,?)', update:'update user set name=?, age=? where id=?', delete: 'delete from user where id=?', queryById: 'select * from user where id=?', queryAll: 'select * from user' }; module.exports = user;
emacs dao/userDao.js
:
// 实现与MySQL交互 var mysql = require('mysql'); var $conf = require('../conf/db'); var $util = require('../util/util'); var $sql = require('./userSqlMapping'); // 使用连接池,提升性能 var pool = mysql.createPool($util.extend({}, $conf.mysql)); // 向前台返回JSON方法的简单封装 var jsonWrite = function (res, ret) { if(typeof ret === 'undefined') { res.json({ code:'1', msg: '操作失败' }); } else { res.json(ret); } }; module.exports = { add: function (req, res, next) { pool.getConnection(function(err, connection) { // 获取前台页面传过来的参数 var param = req.query || req.params; // 建立连接,向表中插入值 // 'INSERT INTO user(id, name, age) VALUES(0,?,?)', connection.query($sql.insert, [param.name, param.age], function(err, result) { if(result) { result = { code: 200, msg:'增加成功' }; } // 以json形式,把操作结果返回给前台页面 jsonWrite(res, result); // 释放连接 connection.release(); }); }); } };
util目录
emacs util/util.js
:
// 提升性能 module.exports = { extend: function(target, source, flag) { for(var key in source) { if(source.hasOwnProperty(key)){ flag ? (target[key] = source[key]) : (target[key] === void 0 && (target[key] = source[key])); } } return target; } };
添加路由
emacs routes/users.js
:
// 在文件开头添加以下代码 var userDao = require('../dao/userDao'); // 添加以下路由 // 增加用户 router.get('/addUser', function(req, res, next) { userDao.add(req, res, next); });
测试
为了方便, 前面实现的是get请求的add方法, 所以可以直接在浏览器中使用地址添加数据到数据库. http://localhost:3000/users/addUser?name=xyz&age=18
根据返回的内容, 判断是否成功. 如果成功, 在数据库中应该可以看到添加了一条新数据.
代码组织
路由都写在 routes
目录下, 然后通过 module.exports = router 将里面的处理方法导出.
在入口文件 app.js
中, 使用 var users = require('./routes/users') 这种语句, 将处理方法赋给 app.js
中的变量, 再使用 app.use('/path', middle) 将路径与处理方法绑定.
以后, 一级路径(如'/users'), 就在 app.js
中与相应的模块进行绑定, 而二级或者更高级的路径(如'/users/pinvon'), 就在路由 routes/users.js
中, 将具体的路径与相应的中间件进行绑定.
关于数据库, 对于数据库中的每一个表, 有一个相应的文件(如'dao/userSqlMapping.js')来编写所需要用到的SQL语句, 然后再有一个相应的文件(如'dao/userDao.js')来作为数据库和前端的中间处理程序. 即, 一个表会有两个对应的文件, 来实现对数据库的操作.
前后端数据传递
后端:
result = { code: 200, msg:'增加成功' }; res.json(result);
前端:
success: function (data, status) { if (status == 'success') { console.log(data); layer.msg('注册成功'); setTimeout(function () { location.href = 'login'; }, 2000); } }, error: function (data, err) { console.log(data); alert('fail'); }
打印结果如下图所示:
可以根据 code
的值, 来判断下一步该怎么处理.
问题记录
- 注册时使用post方法提交数据, 在后台进入post对应的中间件处理, 将数据存储到数据库, 存储完成后回到post方法继续执行, 会进入到get方法, 而代码中没在post方法里面写明会渲染或重定向到get. 目前的方案是在get()中判断参数, 如果路径中带参数, 则不让渲染注册页面.
- Node.js的线程: 如果函数有回调函数, 该函数的返回值依赖于回调函数, 则函数的返回值一般不是我所预期的, 因为函数会先返回, 然后再去执行回调函数.
Generated by Emacs 25.x(Org mode 8.x)
Copyright © 2014 - Pinvon - Powered by EGO