从零开始学习nodejs(四)nodejs+express+mysql搭建后台服务(上)

系列文章github项目地址(最终版):https://github.com/zliuyang1287/MyBlog
前言
前面已经了解了express快速搭建web项目的应用,了解了各个文件目录的作用,也编写了一个简单的页面测试了一下,所有的这些工作只是了解了express的工作流程,从这一篇开始慢慢搭建后台服务。在前面的文章里提到过这么一段代码位于app.js里

// 设置模板 其中__dirname为全局变量,表示当前正在执行的脚本所在的目录
// 设置模版文件所在路径,也就是试图文件,都放在views层
app.set('views', path.join(__dirname, 'views'));
// // 设置模版引擎,比如jade、ejs
app.set('view engine', 'ejs');

这段代码已经被我注释掉了,原因是这里是设置要被渲染的页面的,而且ejs跟express也是融合性极好的模版引擎。有了这个模版引擎我们可以直接前后端放在一块(不好解释,可以理解为Java中的servlet+jsp,而且ejs也跟jsp语法类似),连接数据库后可以直接将返回的查询信息通过模版引擎渲染到页面中直接返回一个HTML页面给用户,对于小的项目这是很好的选择。本来想写一个例子,但是代码在我无数次的修改中已经面目全非,也没时间了。因为我主要想做的是前后台分离式的demo,下面要写的是搭建后台服务。
正题
开始之前先把数据库建好,建立一个简单的USER_INFO数据库表
在这里插入图片描述
看一下项目修改之后的目录结构
在这里插入图片描述
相比之前目录结构多了conf文件夹,用于配置访问数据库的连接信息。多了dao文件夹用于访问数据库,多了util文件夹用于封装一些工具类。缺失了views文件夹,既然要前后端分离当然不需要这些页面了。
再看一下我想得到的最终效果
在这里插入图片描述
标准的后端数据返回格式。下面是实现流程,依然从app.js出发
app.js
主要改动有两个,一个是引入自己编写的json格式化工具,另一个是把404与异常错误改为json格式返回(原先是返回错误页面,既然不需要在这里展示页面就改为返回错误信息描述),其余的不动。

var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');

// 引入路由
var indexRouter = require('./routes/index');
// 引入json格式化工具
var JsonFormat = require('./util/util').JsonFormat;

// 创建一个express实例
var app = express();

// 日志中间件
app.use(logger('dev'));
// json解析中间件
app.use(express.json());
// 解析urlencoded请求体的中间件
app.use(express.urlencoded({ extended: false }));
// cookie解析中间件
app.use(cookieParser());
// public设置为静态文件夹
app.use(express.static(path.join(__dirname, 'public')));

// 设置路由
app.use('/', indexRouter);

// 捕捉404错误信息并给出404提示,可以自定义提示信息
app.use(function(req, res, next) {
  JsonFormat.rtnError(res,'404 NOT FOUNT');
});

// 异常或错误信息处理
app.use(function(err, req, res, next) {
  JsonFormat.rtnError(res,err.message);
});

module.exports = app;

util.js
既然说到了json格式化工具,就看一下里面怎么写的。里面的res就是response对象,res.json()表示传送JSON响应,三个方法分别响应操作成功、操作失败和带查询数据的逻辑处理。其中0表示成功,1表示失败

// 封装返回消息
var rtnSuccess = function(res){
    var obj = {"code":0,"msg":"操作成功"}
    res.json(obj);
};
var rtnError = function(res,message){
    var obj = {"code":1,"msg":message}
    res.json(obj);
};
var rtnObj = function(res,data){
    var obj = {"code":1,"msg":"操作成功","data":data}
    res.json(obj);
};

var JsonFormat = {rtnError,rtnObj,rtnSuccess};

module.exports = {
    JsonFormat
};

conf.js
划重点,最主要的部分,在这里设置数据库的连接信息,既然要连接MySQL数据库,自然需要MySQL的依赖包

npm install mysql
// conf/db.js
// MySQL数据库连接配置
var mysql = require('mysql');

var dbconf = {
    // 主机名
    host: '127.0.0.1',
    // 数据库用户名
    user: 'root',
    // 数据库密码
    password: '123456',
    // 链接的数据库
    database: 'blog',
    // 链接的端口
    port: 3306
}

// 创建数据库连接池
var pool = mysql.createPool(dbconf);

// 将连接池提供给它用
module.exports = pool;

user.js
学习的过程中,大多数教程直接把sql放在数据库连接后的请求中,个人不是很适应,一个是不方便管理一个是显得太乱。受Java的影响我更喜欢把数据库访问的东西拿出来,类似于当作一个实体类,这么说也不严谨,反正就是为了方便管理。

//建立操作数据库的sql
var user = {
	insert:'INSERT INTO USER_INFO(ACCOUNT,PASSWORD,NAME,CREATE_DATE) VALUES(?,?,?,?)',
	update:'UPDATE USER_INFO SET ACCOUNT=?, NAME=? WHERE ID=?',
	delete: 'DELETE FROM USER_INFO WHERE ID=?',
	queryById: 'SELECT * FROM USER_INFO WHERE ID=?',
    queryAll: 'SELECT * FROM USER_INFO',
    updatePsd:'UPDATE USER_INFO SET PASSWORD=? WHERE ID=?'
};
 //将sql提供给它用
module.exports = user;

userDao.js
这是访问数据库的主要实现部分,类比Java这里就是service层了
一共提供了6个方法,分别是新建用户、修改用户、删除用户、查询单个用户、查询多个用户、修改密码。后续有别的功能需求可以不断的添加,代码过多,看一个就可以。我已经注释的非常详细了

// 实现与MySQL交互
// 获取连接池
var pool = require('../../conf/db');
// 获取json格式化工具类
var json = require('../../util/util').JsonFormat;
// 获取编写好的sql语句
var sql = require('./user');
// 暴露方法给它用
module.exports = {
	//增加
	add: function (req, res, next) {
		// 获取前台页面传过来的参数
		// ps:res和rsp有哪些属性可以去菜鸟教程的express部分查看,或者我在文末附上
		var param = req.query || req.search;
		// 获取数据库的连接
		pool.getConnection(function (err, connection) {
			// 捕捉链接错误信息并返回
			if (err) {
				json.rtnError(res,"数据库连接失败:"+err.message);
				return;
			}
			// 执行sql语句,这里是插入一条信息query一共有三个参数,第一个是sql语句。第二个是参数数组,一定要和数据库的
			// 数据类型相对应,也要跟sql语句的占位符相对应。第三个是回调函数,err代表访问是否出错,result代表本次访问的回执信息
			connection.query(sql.insert, [param.account, param.password, param.name, new Date()], function (err, result) {
				// 插入失败,返回错误信息
				if(err){
					json.rtnError(res,err.message);
					return;
				}
				// 插入成功返回操作成功,result可以自己打印看一下,当只做查询时返回查询到的数据,其他诸如增删改操作返回的是一个
				// 对象,其中affectedRows就是受影响的行数,其余的属性可以自行打印看看
				if (result.affectedRows>0) {
					json.rtnSuccess(res);
				}
				// 释放连接,访问数据库完成一定要及时干掉此次连接请求,不然一会你的数据库就崩死了 
				connection.release();
			});
		});
	},
	delete: function (req, res, next) {
		// delete by Id
		pool.getConnection(function(err, connection) {
			if (err) {
				json.rtnError(res,"数据库连接失败:"+err.message);
				return;
			}
			var id = parseInt(req.query.id);
			connection.query(sql.delete, id, function(err, result) {
				if(err){
					json.rtnError(res,err.message);
					return;
				}
				if(result.affectedRows > 0) {
					json.rtnSuccess(res);
				}
				connection.release();
			});
		});
	},
	queryById: function (req, res, next) {
		var id = req.query.id; 
		if (id==null) {
			json.rtnError(res,"删除失败!未获取到要删除的信息");
			return;
		}
		pool.getConnection(function(err, connection) {
			if (err) {
				json.rtnError(res,"数据库连接失败:"+err.message);
				return;
			}
			connection.query(sql.queryById, id, function(err, result) {
				if(err){
					json.rtnError(res,err.message);
					return;
				}
				if(result){
					json.rtnObj(res,result);
				}
				connection.release();
			});
		});
	}
};

index.js
routes下的index依旧是配置路由信息,类比Java这就是controller层。

var express = require('express');
var router = express.Router();
// 引入数据库的访问方法,类比Java这里就是注入Service
var userDao = require('../dao/user/userDao');

//配置路由
// post就是post请求
router.post('/addUser', function(req, res, next) {
  // 调用userDao中的add方法
	userDao.add(req, res, next);
});
// get请求,习惯上数据添加修改都用post,查询删除用get
router.get('/deleteUser', function(req, res, next) {
	userDao.delete(req, res, next);
});
router.post('/updateUser', function(req, res, next) {
	userDao.update(req, res, next);
});
router.post('/updatePsd', function(req, res, next) {
	userDao.updatePsd(req, res, next);
});
router.get('/queryUserById', function(req, res, next) {
	userDao.queryById(req, res, next);
});
router.get('/queryAllUser', function(req, res, next) {
	userDao.queryAll(req, res, next);
});
module.exports = router; 

以上就是全部的文件信息,下面用postman测试一下效果
插入信息
在这里插入图片描述
查看一下数据库,插入成功
在这里插入图片描述
删除信息
删掉id为3的张三的信息
在这里插入图片描述
可见张三已被干掉
在这里插入图片描述
查询信息
把我刚刚插入的信息查出来
在这里插入图片描述
好了,经过测试没有问题,基本的服务器搭建完毕。

看似没问题了实则问题一大堆,于我而言,,最受不了的就是代码臃肿、重复。userDao.js里面的代码明显还可以深入修改,封装优化。路由也需要重新整理,后面路由多了挤成块既不美观也不易于维护,要重新整理。当然,有时间再说。。。
在这里插入图片描述

后面如果前后端分离式,前端可能要用一下vue了,依然从0开始,后端出身的我也要与时俱进~

附:express框架的request和response对象
request:

  • req.app:当callback为外部文件时,用req.app访问express的实例
  • req.baseUrl:获取路由当前安装的URL路径
  • req.body / req.cookies:获得「请求主体」/ Cookies
  • req.fresh / req.stale:判断请求是否还「新鲜」
  • req.hostname / req.ip:获取主机名和IP地址
  • req.originalUrl:获取原始请求URL
  • req.params:获取路由的parameters
  • req.path:获取请求路径
  • req.protocol:获取协议类型
  • req.query:获取URL的查询参数串
  • req.route:获取当前匹配的路由
  • req.subdomains:获取子域名
  • req.accepts():检查可接受的请求的文档类型
  • req.acceptsCharsets / req.acceptsEncodings /
  • req.acceptsLanguages:返回指定字符集的第一个可接受字符编码
  • req.get():获取指定的HTTP请求头
  • req.is():判断请求头Content-Type的MIME类型

response:

  • res.app:同req.app一样
  • res.append():追加指定HTTP头
  • res.set()在res.append()后将重置之前设置的头
  • res.cookie(name,value [,option]):设置Cookie
  • opition: domain / expires / httpOnly / maxAge / path / secure /
    signed
  • res.clearCookie():清除Cookie
  • res.download():传送指定路径的文件
  • res.get():返回指定的HTTP头
  • res.json():传送JSON响应
  • res.jsonp():传送JSONP响应
  • res.location():只设置响应的Location HTTP头,不设置状态码或者close response
  • res.redirect():设置响应的Location HTTP头,并且设置状态码302
  • res.render(view,[locals],callback):渲染一个view,同时向callback传递渲染后的字符串,如果在渲染过程中有错误发生next(err)将会被自动调用。callback将会被传入一个可能发生的错误以及渲染后的页面,这样就不会自动输出了。
  • res.send():传送HTTP响应
  • res.sendFile(path [,options] [,fn]):传送指定路径的文件-会自动根据文件extension设定Content-Type
  • res.set():设置HTTP头,传入object可以一次设置多个头
  • res.status():设置HTTP状态码
  • res.type():设置Content-Type的MIME类型
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章