Node js web开发简单demo学习笔记


本人于今年1月开始接触node js,接触的时间不长,所以技术水平还有待提高,希望这篇简单的文章能够对大家学习nodejs有所帮助。

一、项目描述

1、项目概要:

主要是使用nodejs实现一个基本的demo的增删改查的功能为在nodejs技术上项目的扩展开发做准备。开发环境主要使用了webstorm,数据库使用了mysql,使用nodejs的express。调用了nodejsmysql扩展包。调用了nodejsnode-uuid扩展包,主要用于uuid 的创建上。调用了nodejsasync扩展包,主要用于对于回调函数的排序处理。

页面模版主要使用了ejs,但在具体使用上将后缀名改为了html

2、项目结构:

Bin目录:www.js文件。创建项目时开发环境自动创建,可以用来修改默认访问地址。

Dao目录:关于数据库相关操作的工具集合。

Config.js:数据库注册信息。

Daobase:数据库基本dqldml操作的工具。

Userdao:对于tb_test_user_表的增删改查的函数的工具类。

Model目录:项目数据模型。

User:数据模型。

Node_modules:开发环境添加的项目相关的库文件。

Public:(未用到)

Routesnodejsexpress包的控制层,路由选择器的功能。用于分配访问路径。

Index.js:基本的页面后台逻辑函数的实现
users.js:(未用到)

Test:自定义测试包

asyncTest.js:用于测试async组件(测试函数可用但是实际函数有问题,留作以后研究点)

Test.js:对于daobase.js功能的测试。

TestDao.js:用于userdao.js功能的测试。

Viewsejs模版页面集合

Error.html:用于显示错误信息

Index.html:登录页面

Insert.html:添加页面

Success.html:用于显示所有数据,功能成功后的跳转页面

Update.html:修改页面

App.js:路由映射表(routes下主要用于跳转逻辑,此文件主要用于映射选择)

Package.json:类似与mavonpom.xml,主要用于依赖包的版本注册

3、数据库设计细节

数据库名:db_test_

表名:tb_test_user_

列名:id 数据类型:varchar 默认长度:50 其他:主键

列名:name 数据类型:varchar 默认长度:50 其他:无

 

列名:password 数据类型:varchar 默认长度:50 其他:无

 

二、详细实现

1www.js文件

//引入app.js文件

var app = require('../app');

2Config.js文件

module.exports={
    host:'localhost',
    user:'root',
    password:'root',
    database:'db_test_',
    ports:3306
};

详解:

Module.exports指将文件暴露给module空间,而文件所代表的为当前函数。(此文件函数为json格式)。 host:为mysqlurluser,password,database,ports分别为:需要用的数据库的帐号、密码、数据库名和端口号。

 

 

 

3、Daobase.js文件

var config=require('./config.js');//引入配置文件
var mysql=require('mysql');//引入mysql驱动
var pool=mysql.createPool(config);//创建数据库连接池
//dql函数(用于查询的函数)
exports.executeQuery=function(sql, data, callback){

//创建连接,并在其回调函数内设置相关操作(nodejs的相关操作都在回调函数里,问题较大,加大了代码复杂度
    pool.getConnection(function(err,conn){
        if(err){
            callback(err,null,null);
        }else{

/*与dml的回调函数参数表不同,其他类似

Qerr:当正确时返回null,错误时返回有用值

Vals:用于存储返回值信息,返回的为一个对象数组,需用下表加表的列名取得值,示例如下:vals[0].name

Fields:返回表结构的相关信息。(本人未如何使用)
  */

          conn.query(sql,data,function(qerr, vals, fields){

//重置数据库连接
                conn.release();

//用于传入回调函数,处理数据
                callback(qerr,vals,fields);
            });
        }
    });
};
//dml函数(用于增加、修改、删除的函数)
exports.executeUpdate function(sql, data, callback) {
    pool.getConnection(function(err, conn) {
        if (err) {
            callback(err, nullnull);
        } else {

//data用于占位符的数据传入,一些意外的情况本人还未测试
            conn.query(sql, data, function(qerr, result) {
                //释放连接
                conn.release();
                //事件驱动回调
                callback(qerr, result);
            });
        }
    });
};

 

 

4、userdao.js文件

var DaoBase = require('./DaoBase');//引入dbutil
var UUID = require('node-uuid');//引入uuid模块
var user_DB = require('../model/User');//引入模型模块
var userDB new user_DB();//实例化模型模块
//添加用户
exports.InsertUser=function(params, callback){
    var data=[];//写差了,应该用实例化后的模型,但是不影响使用
    var sql='INSERT INTO tb_test_user_ (id,NAME,PASSWORD) VALUES(?,?,?)';
    var id=UUID.v4();
    data.push(id);//按占位符顺序加入数组
    data.push(params.name);
    data.push(params.password);
    DaoBase.executeUpdate(sql,data,callback);
};
//修改用户
exports.UpdateUser=function(params,id, callback){
    var sql='UPDATE  tb_test_user_ SET NAME=?,PASSWORD=? WHERE id=?';
    var data=[];
    data.push(params.name);
    data.push(params.password);
    data.push(id);
    DaoBase.executeUpdate(sql,data,callback);
};
//删除用户
exports.DeleteUser=function(id,callback){
    var sql='delete from tb_test_user_  where id=?';
    var data=[];
    data.push(id);
    DaoBase.executeUpdate(sql,data,callback);
};
//查询所有用户
exports.FindAll=function(callback){
    var sql='select * from tb_test_user_';
    DaoBase.executeQuery(sql,callback);
};
//根据id查询
exports.FindById=function(id,callback){
    var sql='select * from tb_test_user_ where id=? ';
    var data=[];
    data.push(id);
    DaoBase.executeQuery(sql,data,callback);
};
//登陆验证
exports.UserLogin=function(params,callback){
    var sql='select * from tb_test_user_ where name=? and password=?';
    var data=[];
    data.push(params.name);
    data.push(params.password);
    DaoBase.executeQuery(sql,data,callback);
}

5、user.js文件

module.exports=User;
function User(){
    this.tableName='tb_test_user_';
    this.id='id';
    this.name='name';
    this.password='password';
}

6index.js文件

var express = require('express');//引入express包
var userDao=require('../dao/UserDao.js');//引入userdao文件
var user_DB = require('../model/User');//引入user实体

//修改初始化
exports.update=function(req,res){
  var id=req.query.id;//nodejs 的get获取传参办法使用req.query.参数名
  console.log(id);
  userDao.FindById(id,function(qerr, vals,fields){
    if(!(qerr==null)){

//选择渲染ejs模版并跳转传参
      res.render('error',{
        message:'寻找修改元素失败'
      });
    }

//获得数据库里面的信息并传到页面(请注意这里用到了多重回调函数嵌套)
    var username=vals[0].name;
    var password=vals[0].password;
    var id=vals[0].id;
    res.render('update',{
      title:'修改数据',
      username:username,
      password:password,
      id:id
    });
  });
};
//修改(对于修改页面的初始化工作)
exports.doUpdate=function(req,res){
  var id=req.body.id;//post传值的接收方式req.Body.参数名(post传值需要)
  var name=req.body.username;
  var password=req.body.password;
  var user=new user_DB();
  user.name=name;
  user.password=password;
  userDao.UpdateUser(user,id,function(qerr, result){
    if(!(qerr==null)){
      res.render('error',{
        message:'修改失败'
      });
    }

//用影响行数去判定dml操作是否成功(请注意即使影响行数为0,函数依然不返回错误)
    if(result.affectedRows>0){
      console.log('success');
      userDao.FindAll(function(qerr,vals,fields){
        var result=vals;
        res.render('success',{
          title:'修改成功',
          result:result
        });
      });
    }
  });
};
//删除
exports.delete=function(req,res){
  var id=req.query.id;
  userDao.DeleteUser(id,function(qerr, result){
    if(!(qerr==null)){
      console.log('error');
      res.render('error',{
        message:'删除失败'
      });
    }
    if(result.affectedRows>0){
      console.log('success');
      userDao.FindAll(function(qerr,vals,fields){
        var result=vals;
        res.render('success',{
          title:'删除成功',
          result:result
        });
      });
    }
  });
};
//添加初始化
exports.insert=function(req,res){
  res.render('Insert',{
    title:'添加数据'
  });
};
//添加
exports.doInsert=function(req,res){
  var username=req.body.username;//我觉得这里写的有点重复,可以直接将值赋给实体
  var password=req.body.password;
  var user=new user_DB();
  user.name=username;
  user.password=password;
  userDao.InsertUser(user,function(qerr, result){
    if(!(qerr==null)){
      res.render('error',{
        message:'添加失败'
      });
    }
    if(result.affectedRows>0){
      userDao.FindAll(function(qerr,vals,fields){
        var result=vals;//直接将结果集封装到json里传给页面,由页面去解封处理
        res.render('success',{
          title:'添加成功',
          result:result
        });
      });
    }
  });
};
//登录初始化
exports.login=function(req,res){
  res.render('index',{
    title:'你好'
  });
};
//登录验证
exports.doLogin=function(req,res){
  var username=req.body.username;
  var password=req.body.password;
  var user=new user_DB();
  user.name=username;
  user.password=password;
  userDao.UserLogin(user,function(qerr, vals,fields){
    if((!(qerr==null))||(vals.length<1)){
      res.render('error',{
        message:'登录失败'
      });
    }else{
      userDao.FindAll(function(qerr,vals,fields){
        var result=vals;
        res.render('success',{
          title:'你好',
          result:result
        });
      });
    }
  });
};

7、 Error.html

<h1><%= message %></h1>//只用于显示结果

8、 Index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title><%= title %></title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
  </head>
  <body>
    <h1><%= title %></h1>
    <p>Welcome to <%= title %></p>
    <form method="post" > //表单可不命名(多表单的页面需要进一步尝试),由于get用于初始化了,所以只能用post提交(node js 有use、get、post三个函数用于处理请求,这只是我所知的,如果有其他方式应可以解决只能post提交问题,当然如果使用中间件应该也可以,我刚刚接触对于中间件还不是很熟悉,当然对于进阶中间件还是很重要的)
    <input type="text"  name="username" > //name属性用于服务器端接收
    <input type="password" name="password" > //
    <input type="submit" value="submit">
    </form>
  </body>
</html>

9、 Insert.html //与登录功能相似所以不再赘述

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title><%= title %></title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
</head>
<body>
    <h1><%= title %></h1>
    <form method="post">
        <p>账号名:<input type="text" name="username"></p>
        <p>密码:<input type="text" name="password"></p>
        <p><input type="submit" value="submit"></p>
    </form>
</body>
</html>

10、 Success.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title><%= title %></title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
  </head>
  <body>
    <h1><%= title %></h1>

    <table>

      <% result.forEach(function(name){ %>//迭代遍历取出后台传过来的result值,

函数中的name为result中依次各个元素的别名,用name取出每个数据库中列名的值
      <tr>

        <td><%= name.name %></td>
        <td><%= name.password %></td>
        <td></td>
        <td><href="/delete?id=<%= name.id %>">删除</a></td>//超链接并用get方式传值
        <td><href="/update?id=<%= name.id %>">修改</a></td>
      </tr>
      <% }) %>
    </table>
  <p><href="/Insert">添加</a></p>

  </body>
</html>

11update.html //只是学习用的示例所以修改页面写的有些简略

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title><%= title %></title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
</head>
<body>
<h1><%= title %></h1>
<form method="post">
    <p><%= id %></p>
    <p><input type="text" name="id" value="<%= id %>">  </p>//用于向后台传id,应当设为不可见
    <p><%= username %></p>
    <p>账号名:<input type="text" name="username" value="<%= username %>" ></p>
    <p><%= password %></p>
    <p>密码:<input type="text" name="password" value="<%= password %>"></p>
    <p><input type="submit" value="submit"></p>
</form>
</body>
</html>

12、App.js(以下只展示需要改和自己写的模块)

var routes = require('./routes/index');//引入自己写的控制逻辑文件

//post解析函数(可复用的必用代码)
app.use(bodyParser.urlencoded({
  extendedtrue
}))

//自定义路由(在app.use的第二个参数中写工厂函数,若是可行则可以实现特殊功能
app.use('/delete',routes.delete);//将删除逻辑与删除页面路径对应(访问nodejs时,系统先在app.js文件中寻找路径对应处理函数)
app.get('/update',routes.update);//修改初始化
app.post('/update',routes.doUpdate);//修改页面的post处理
app.get('/Insert',routes.insert);//添加初始化
app.post('/Insert',routes.doInsert);//添加处理函数
//初始路径请放到最下面
app.get('/',routes.login);//登录页面初始化
app.post('/',routes.doLogin);//登录验证

// view engine setup //用于将ejs模版的后缀改为html(据说是3版本后的写法)
app.set('views'path.join(__dirname'views'));//确定模版所在文件夹
app.engine('.html', require('ejs').renderFile);
app.set('view engine''html');

13、package.Json

{
  "name""LoginTest0",
  "version""0.0.0",
  "private"true,
  "scripts": {
    "start""node ./bin/www"
  },
  "dependencies": {
    "async""~1.4.2", //自己添加
    "node-uuid"">= 1.4.1",//自己添加
    "mysql""~2.9.0", //自己添加
    "body-parser""~1.13.2",
    "cookie-parser""~1.3.5",
    "debug""~2.2.0",
    "ejs""~2.3.3",
    "express""~4.13.1",
    "morgan""~1.6.1",
    "serve-favicon""~2.3.0"
  }
}

三、总结

本人新接触nodejs有很多地方都是第一次接触,所以写的这个例子相对来讲只是入门级别,如果有问题希望能给于指正,有问题希望能和大家一起探讨。在写这个例子的过程中,用到了很多回调函数嵌套的情况,一般说来这是一个无可奈何的事情,但是这样加大了程序的阅读难度。我希望能在之后的学习中找到一种能够提高代码可读性的办法。在这个例子中有很多回调函数实际是重复的,这实际上是一种冗余。希望大家能够借鉴我好的方面,摒除我坏的方面。

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值