当前位置: 首页 > 工具软件 > Restify > 使用案例 >

关于Nodejs搭建后台API服务(Mysql-Restify)

衡泰
2023-12-01

尝试一下写些技术的东西, 之前在公司一直是用C#写的WCF后台. 对于跨域调用API虽然也支持, 但是需要做的配置也挺繁琐, 所以试下不一样的后台技术, NodeJs .

由于只做API调用, 所以用了Restify 插件而不是Express .

所以先全局安装下 restify  : npm install restify -g  (-g就是全局,不然就是当前路径下安装).​

装好nodejs后第一步是创建项目环境:

在电脑新建文件夹(F:\NodeTest) 在NodeJs的Console端CD进去,

输入npm init  ,配置下项目信息


npm init

​然后在项目里安装下数据库连接件 node-mysql (当然全局安装也没问题)

npm install node-mysql -save (写到刚刚配置的package.json​里)

然后是刚刚在init上的Entry Point 写的入口点(首先启动的js)

用文本编辑器新建app.js 内容:

var server=require("./JsModule/RestServer.js");

server.start();

看到require 的路径了吧,对了,接下来就是再创建它. sever是什么, start是什么方法, 都在这个js文件里, 至于require, 则是Nodejs自带, 可以理解为JAVA的import包.

新建文件夹JsModule, 新建js RestServer.js


现在的项目结构

​var restify = require('restify');

var Guest=require("./Controll/GuestControll.js");

var MySql=require("./MysqlHelper.js");

function start(){   

var server = restify.createServer(); 

  server.use(restify.bodyParser());   

server.use(restify.queryParser()); 

  server.use(restify.CORS());  

 var SqlPool=Object.create(MySql.MysqlHelper);  

 SqlPool.InitConnect(); 

 Guest.GuestControll(server,SqlPool);  

 server.get("/getservertime",function(req,res,next)  

 {       

     var timestamp = date.parse(new date());  

     res.send(timestamp);  

 })   

server.listen(5203, function() {      console.log('%s listening at %s', server.name, server.url);    });}

exports.start=start;

第一句require没有路径, 因为是全局安装的module,可以用名称直接搜索到restify, 

第二句Guest是一个MVC式的controller. 负责将发过来的请求转发处理, 我们这次的例子是查询一个住客信息.

第三句Mysql则是调用一个数据连接类.

主程序就是 start 这个函数, 在最尾一句export出来. 呼应App.js 的新建的 var obj=XXX; obj.start();

那start函数在做的是 ,前四句使用restify提供的server, 并添加参数处理,跨域支持.

第五,六句则是初始化一个数据连接池

第七句 是将服务和连接池传到Controller去加工.

第八句 server.get() 就是注册一个新的请求监听, 其实在Controller里我们也是做这种请求的注册, 只是为了封装起来,分散开方便阅读和处理. 这里是请求服务器时间, 直接回传一个UTC值.

然后最后 调用restify包装过的 server.listen()  Web服务就会启动, 5203 就是部署的端口号, 后面的function是成功后的回调方法

接下来我们先看看数据连接的类, 这是我试错后自己写的哦. 由require路径看出他和RestSever.js是同个文件夹的.

var mysql=require('mysql');
var fs = require('fs');
var MysqlHelper=
{
    SqlPool:false,
    InitConnect:function()
    {
        fs.readFile('./Mysql.json','utf8',function(err,data){
            if(err) throw err;
            var jsonObj = JSON.parse(data);
            SqlPool= mysql.createPool({
              connectionLimit : 3,
              host : jsonObj.host,
              port : jsonObj.port,
              user : jsonObj.user,
              password :jsonObj.password,
              database:jsonObj.database,
              supportBigNumbers:jsonObj.supportBigNumbers,
              multipleStatements:jsonObj.multipleStatements

            });
        });
    },

    SelectTable:function(aTableName,aSelCols,aWhere,aParam,aDataCallback)
    {
        if(SqlPool===false)return false;
        if(aSelCols==="")aSelCols="*";
        if(aWhere==="")aWhere="1=1";
        var selectSQL= ["SELECT "];
        selectSQL.push(aSelCols);
        selectSQL.push(" FROM ");
        selectSQL.push(aTableName);
        selectSQL.push(" WHERE ");
        selectSQL.push(aWhere);
        var runSql=selectSQL.join("");
        console.log(runSql);
        SqlPool.getConnection(function (err, conn) {
            if(aParam){
                conn.query(runSql,aParam,function(err,rows){
                    if (err)
                    {
                        console.log("Con ==> "+err);
                        aDataCallback?aDataCallback(false):0;
                    }
                    var Datas=rows;
                    conn.release();
                    aDataCallback?aDataCallback(Datas):0;
                });
            }else{
                conn.query(runSql,function(err,rows){
                    if (err)
                    {
                        console.log("Con ==> "+err);
                        aDataCallback?aDataCallback(false):0;
                    }
                    var Datas=rows;
                    conn.release();
                    aDataCallback?aDataCallback(Datas):0;
                });
            }
        });
    },

    InsertTableRow:function(aTableName,aInsertCols,aInsertValueArray,aParam,aDataCallback)
    {
        if(SqlPool===false)return false;
        var InsertSQL= ["INSERT INTO "];
        InsertSQL.push(aTableName);
        InsertSQL.push("(");
        for(var i=0; i
        {
            if(i>0){InsertSQL.push(',');}
            InsertSQL.push(aInsertCols[i]);
        }
        InsertSQL.push(")");
        InsertSQL.push(" VALUES(");
        for(var i=0; i
        {
            if(i>0){InsertSQL.push(',');}
            InsertSQL.push(aInsertValueArray[i]);
        }
        InsertSQL.push(");");
        var runSql=InsertSQL.join('');
        console.log(runSql);
        SqlPool.getConnection(function (err, conn) {
            if(aParam){
                conn.query(runSql,aParam,function(err,result){
                    if (err)
                    {
                        console.log("Con ==> "+err);
                        aDataCallback?aDataCallback(-1):0;
                    }
                    var NewId=result.insertId;
                    conn.release();
                    aDataCallback?aDataCallback(NewId):0;
                });
            }else{
                conn.query(runSql,function(err,result){
                    if (err)
                    {
                        console.log("Con ==> "+err);
                        aDataCallback?aDataCallback(-1):0;
                    }
                    var NewId=result.insertId;
                    conn.release();
                    aDataCallback?aDataCallback(NewId):0;
                });
            }
        });
    },

    DeleteTable:function(aTableName,aWhere,aParam,aDataCallback)
    {
        if(SqlPool===false)return false;
        var runSQL= "DELETE FROM ?? WHERE ";
        runSQL = mysql.format(runSQL, [aTableName]);
        runSQL+=aWhere;
        console.log(runSQL);
        SqlPool.getConnection(function (err, conn) {
            if(aParam){
                conn.query(runSQL,aParam,function(err,result){
                    if (err)
                    {
                        console.log("Con ==> "+err);
                        aDataCallback?aDataCallback(-1):0;
                    }
                    var ARows=result.affectedRows;
                    conn.release();
                    aDataCallback?aDataCallback(ARows):0;
                });
            }else{
                conn.query(runSQL,function(err,result){
                    if (err)
                    {
                        console.log("Con ==> "+err);
                        aDataCallback?aDataCallback(-1):0;
                    }
                    var ARows=result.affectedRows;
                    conn.release();
                    aDataCallback?aDataCallback(ARows):0;
                });
            }
        });
    },

    UpdateTable:function(aTableName,aUpdateColArray,aUpdateValueArray,aWhere,aParam,aDataCallback)
    {
        if(SqlPool===false)return false;
        var UpdateSQL= [" UPDATE "];
        UpdateSQL.push(aTableName);
        UpdateSQL.push(" SET ");
        for(var i=0; i
        {
            if(i>0){UpdateSQL.push(',');}
            UpdateSQL.push(aUpdateColArray[i]);
            UpdateSQL.push('=');
            UpdateSQL.push(aUpdateValueArray[i]);
        }
        UpdateSQL.push(" WHERE ");
        UpdateSQL.push(aWhere);
        var runSql=UpdateSQL.join('');
        console.log(runSql);
        SqlPool.getConnection(function (err, conn) {
            if(aParam){
                conn.query(runSql,aParam,function(err,result){
                    if (err)
                    {
                        console.log("Con ==> "+err);
                        aDataCallback?aDataCallback(-1):0;
                    }
                    var ARows=result.affectedRows;
                    conn.release();
                    aDataCallback?aDataCallback(ARows):0;
                });
            }else{
                conn.query(runSql,function(err,result){
                    if (err)
                    {
                        console.log("Con ==> "+err);
                        aDataCallback?aDataCallback(-1):0;
                    }
                    var ARows=result.affectedRows;
                    conn.release();
                    aDataCallback?aDataCallback(ARows):0;
                });
            }
        });
    },

    ExecuteNoqueryCmd:function(aSql,aParam,aDataCallback)
    {
        if(SqlPool===false)return false;
        SqlPool.getConnection(function (err, conn) {
            if(aParam){
                conn.query(aSql,aParam,function(err,result){
                    if (err)
                    {
                        console.log("Con ==> "+err);
                        aDataCallback?aDataCallback(false):0;
                    }
                    var ARows=result.affectedRows;
                    conn.release();
                    aDataCallback?aDataCallback(ARows):0;
                });
            }else{
                conn.query(aSql,function(err,result){
                    if (err)
                    {
                        console.log("Con ==> "+err);
                        aDataCallback?aDataCallback(false):0;
                    }
                    var ARows=result.affectedRows;
                    conn.release();
                    aDataCallback?aDataCallback(ARows):0;
                });
            }
        });
    },

    ExecuteQueryCmd:function(aSql,aParam,aDataCallback)
    {
        if(SqlPool===false)return false;
        SqlPool.getConnection(function (err, conn) {
            if(aParam){
                conn.query(aSql,aParam,function(err,rows){
                    if (err)
                    {
                        console.log("Con ==> "+err);
                        aDataCallback?aDataCallback(false):0;
                    }
                    var Datas=rows;
                    conn.release();
                    aDataCallback?aDataCallback(Datas):0;
                });
            }else{
                conn.query(aSql,function(err,rows){
                    if (err)
                    {
                        console.log("Con ==> "+err);
                        aDataCallback?aDataCallback(false):0;
                    }
                    var Datas=rows;
                    conn.release();
                    aDataCallback?aDataCallback(Datas):0;
                });
            }
        });
    }
}
exports.MysqlHelper=MysqlHelper;

第二句require('fs')是nodejs提供的内部读写文件的包, 我们需要有一个数据的配置文件去存放连接和路径,InitConnect 里读取 ./Mysql.json 初始了一个连接池 然后这个Pool就在RestServer里初始并一直存在了. 至于怎么关闭池 我还没写. 应该就是 RestSever再响应个Server.close 然后调用这个类的ClosePool 这样.

Mysql.json 内容:

{
"host":"127.0.0.1",
"port":"3306",
"user":"root",
"password":"test",
"database":"basicdb",
"supportBigNumbers":"true",
"multipleStatements":"true"
}

连接类里面的增删查改方法都要用回调函数才能获取的执行结果,然后这个回调在后面的代码还会多加一个回调aDataCallback 才能对执行结果进行精加工, 这就是NodeJs的事件触发机制, 回调吧少年.

因为是API后台, 没有V只剩MC, 我们先看看Controller吧.也是简单的处理代码.

由require看出,我们需要在JsModule下再建一个文件夹Controll,再在里面新建GuestControll.js

var Guest=require("../Model/Guest.js");

function GuestControll(app,Mysql)

{

var GuestModel=Object.create(Guest.GuestModel);

app.get('/guest/gettodayguest', GetTodayGuests);  //查询今天客人

app.get('/guest/getroombooking', GetRoomBooking); //查询房间预订信息

app.get('/guest/getguestinfobyid', GetGuestInfoById); //根据客人id获取信息

app.post('/guest/bookroom', NewGuest); //预订客房

app.post('/guest/checkin', Checkin); //入住客房

app.post('/guest/checkout', Checkout); //退房

app.post('/guest/cancelbooking', CancelBooking); //取消预订

app.post('/guest/overstay', OverStay); //续住

function GetTodayGuests(req, res, next) {

console.log("GetTodayGuests query:"+JSON.stringify(req.query));

var Today=req.params.today;

GuestModel.GetTodayGuests(Mysql,Today,function(Data){

res.charSet('utf-8');

res.send(Data);

});

}

function NewGuest(req, res, next){

res.send('0');

}

function Checkin(req, res, next) {

console.log("Checkin param:"+JSON.stringify(req.params));

var RoomId=req.params.roomid;

GuestModel.Checkin(Mysql,RoomId,function(Rst){

res.charSet('utf-8');

var SR={iRst:Rst};

res.send(SR);

});

}

function Checkout(req, res, next) {

console.log("Checkout param:"+JSON.stringify(req.params));

var RoomId=req.params.roomid;

GuestModel.Checkout(Mysql,RoomId,function(Rst){

res.charSet('utf-8');

var SR={iRst:Rst};

res.send(SR);

});

}

function CancelBooking(req, res, next) {

  console.log("CancelBooking param:"+JSON.stringify(req.params));

  var RoomId=req.params.roomid;

  var GuestStr=req.params.guestStr;

  var GuestArr=eval_r(GuestStr);

  console.log(GuestArr);

  GuestModel.CancelBooking(Mysql,RoomId,GuestArr,function(Rst){

res.charSet('utf-8');

var SR={iRst:Rst};

  res.send(SR);

  });

}

function OverStay(req, res, next) {

console.log("OverStay param:"+JSON.stringify(req.params));

  var RoomId=req.params.roomid;

  var StayTime=req.params.staytime;

GuestModel.OverStay(Mysql,RoomId,StayTime,function(Rst){

res.charSet('utf-8');

var SR={iRst:Rst};

res.send(SR);

});

}

function GetRoomBooking(req, res, next)

{

console.log("GetRoomBooking query:"+JSON.stringify(req.query));

var RoomId=req.params.roomid;

var NowTime=req.params.thistime;

GuestModel.GetRoomBooking(Mysql,RoomId,NowTime,function(Data){

res.charSet('utf-8');

res.send(Data);

});

}

function GetGuestInfoById(req, res, next)

{

console.log("GetGuestInfoById query:"+JSON.stringify(req.query));

var UserId=req.params.uid;

GuestModel.GetGuestInfoById(Mysql,UserId,function(Data){

res.charSet('utf-8');

res.send(Data);

});

}

}

exports.GuestControll=GuestControll;

Controller都是中转控制啦, 业务逻辑都在Module层里, 第一句就告诉我们又要再建一个Module文件夹和Guest.js 的Module. 唯一让我觉得不够爽的地方是注册各个请求的接收参数名, 这个必须由后台私下和前端事先约定, 在nodejs上无法自描述...

var JsOper=require("../Tool/JsOper.js");
var DataTable=require("../Tool/CDataTableName.js");
var GuestModel={
GetTodayGuests:function(MySql,aUTCDate,aResponse) {
var QueryCmd=['SELECT t1.ROOM_ID,t1.GASTNR,t1.GASTNAME,t2.SEX,t2.VIP,t1.ANREISE,t1.ABREISE,t1.CHECK_FLAG '];
QueryCmd.push(' FROM  ',DataTable.TableGuestCheckIn,' t1, ',DataTable.TableGuestInfo,' t2 ' );
QueryCmd.push(' WHERE t1.GASTNR=t2.NUMMER  AND ((t1.ANREISE<? AND t1.ABREISE>=?) OR  CHECK_FLAG=?) AND CHECK_FLAG<>? ' );
QueryCmd.push(' ORDER BY t1.ROOM_ID ' );
var NowDate=JsOper.GetDateStr(aUTCDate,0);
var NextDate=JsOper.GetDateStr(aUTCDate,1);
var QueryPara=[NextDate,NowDate,DataTable.FlagCheckIn,DataTable.FlagCheckOut];
var runCmd=QueryCmd.join("");
  MySql.ExecuteQueryCmd(runCmd,QueryPara
  ,function(data){
  if(data===false){
  var DataRst={iRst:-1,iGuestList:[]};
  aResponse?aResponse(DataRst):0;
  }
 
  var LastRid=-1,ThisRid=0,GuestArray=[],RoomGuest=[];
  for(var i in data)
  {
  ThisRid = data[i].ROOM_ID;
                if (LastRid == -1) LastRid = ThisRid;
               if (LastRid != ThisRid)
               {
                   GuestArray.push({iRoomId:LastRid,iGuest:RoomGuest});
                   
                   RoomGuest = [];
                   LastRid = ThisRid;
               }
               RoomGuest.push(
               {
                   iGuestNo :data[i].GASTNR,
                   iGuestName :data[i].GASTNAME,
                   iSex : GetSexName(data[i].SEX),
                   iVip : data[i].VIP,
                   iCheckFlag :data[i].CHECK_FLAG,
                   iCheckOutTime :Date.parse(data[i].ABREISE)/1000,
                   iCheckInTime :Date.parse(data[i].ANREISE)/1000
               });
               
  }
  if (LastRid > 0) GuestArray.push({iRoomId:LastRid,iGuest:RoomGuest});
  var DataRst={iRst:0,iGuestList:GuestArray};
aResponse?aResponse(DataRst):0;
});
},


GetRoomBooking:function(MySql,aRoomId,aNowTime,aResponse) {
var QueryCmd=['SELECT t1.GASTNR,t1.GASTNAME,t2.SEX,t2.VIP,t1.ANREISE,t1.ABREISE,t1.CHECK_FLAG '];
QueryCmd.push(' FROM  ',DataTable.TableGuestCheckIn,' t1, ',DataTable.TableGuestInfo,' t2 ' );
QueryCmd.push(' WHERE t1.GASTNR=t2.NUMMER  AND ROOM_ID=? AND t1.ABREISE>=? AND CHECK_FLAG=? ' );
var ThisDate=new Date(aNowTime*1000);
var NowDate=JsOper.ToLongDateStr(ThisDate);
var QueryPara=[aRoomId,NowDate,DataTable.FlagEmpty];
var runCmd=QueryCmd.join("");
  MySql.ExecuteQueryCmd(runCmd,QueryPara
  ,function(data){
  if(data===false){
  var DataRst={iRst:-1,iGuest:[]};
  aResponse?aResponse(DataRst):0;
  }
  var RoomGuest=[];
  for(var i in data)
  {
               RoomGuest.push(
               {
                   iGuestNo :data[i].GASTNR,
                   iGuestName :data[i].GASTNAME,
                   iSex : GetSexName(data[i].SEX),
                   iVip : data[i].VIP,
                   iCheckFlag :data[i].CHECK_FLAG,
                   iCheckOutTime :Date.parse(data[i].ABREISE)/1000,
                   iCheckInTime :Date.parse(data[i].ANREISE)/1000
               });
               
  }
  var DataRst={iRst:0,iGuest:RoomGuest};
aResponse?aResponse(DataRst):0;
});
},


GetGuestInfoById:function(MySql,aUserId,aResponse)
{
  MySql.SelectTable(DataTable.TableGuestInfo,"","NUMMER="+aUserId,false,
  ,function(data){
  if(data===false){
  var DataRst={iRst:-1,iGuest:[]};
  aResponse?aResponse(DataRst):0;
  }
  var Guest=[];
  for(var i in data)
  {
               Guest.push(
               {
                   iGuestNo :data[i].GASTNR,
                   iGuestName :data[i].GASTNAME,
                   iCity:data[i].ORT,
                   iEmail:data[i].EMAIL,
                   iLang:data[i].SPRACHE,
                   iMobile:data[i].TELEX,
                   iNation:data[i].NATION,
                   iSex : GetSexName(data[i].SEX),
                   iVip : data[i].VIP,
                   iCardNo:data[i].PASSPORT
               });
  }
  var DataRst={iRst:0,iGuest:Guest};
aResponse?aResponse(DataRst):0;
});
},
NewGuest:function(req, res, next){
res.send('0');
},


Checkin:function(MySql,aRoomId) {
   var Today = JsOper.GetDateStr(0,0); //今天
var Tomorrow=JsOper.GetDateStr(0,1); //明天
var QPara=[aRoomId,Today,Tomorrow,,DataTable.FlagEmpty];
MySql.SelectTable(DataTable.TableGuestCheckIn,"1"," ROOM_ID=?  AND ANREISE <? AND ABREISE>?  AND CHECK_FLAG=? ",QPara
  ,function(data){
  if(data===false){aResponse?aResponse(-1):0;return;}
  if(data.length===0){aResponse?aResponse(-4):0;return;}
var updateCol=['CHECK_FLAG','ANREISE'];
var updateVal=['?','NOW()'];
var UPara=[DataTable.FlagCheckIn,aRoomId,Today,Tomorrow,DataTable.FlagEmpty];
MySql.UpdateTable(DataTable.TableGuestCheckIn,updateCol,updateVal," ROOM_ID=?  AND ANREISE <? AND ABREISE>?  AND CHECK_FLAG=? ",UPara,
function(Rst)
{
if(Rst===false)Rst=-1;
  aResponse?aResponse(Rst):0;
});
});
},

Checkout:function(MySql,aRoomId) {
   var updateCol=['CHECK_FLAG','ABREISE'];
var updateVal=['?','NOW()'];
var UPara=[DataTable.FlagCheckOut];
MySql.UpdateTable(DataTable.TableGuestCheckIn,updateCol,updateVal,"ROOM_ID="+aRoomId,UPara,
function(Rst)
{
if(Rst===false)Rst=-1;
  aResponse?aResponse(Rst):0;
});
},


OverStay:function(MySql,aRoomId,aStayTime,aResponse){
var StayDate=new Date(aStayTime*1000);
var updateCol=['ABREISE'];
var updateVal=['?'];
var UPara=[JsOper.ToLongDateStr(StayDate),DataTable.FlagCheckIn];
MySql.UpdateTable(DataTable.TableGuestCheckIn,updateCol,updateVal," CHECK_FLAG=? AND ROOM_ID="+aRoomId,UPara,
function(Rst)
{
if(Rst===false)Rst=-1;
  aResponse?aResponse(Rst):0;
});
},


CancelBooking:function(MySql,aRoomId,aGuestArr,aResponse) {
  if(aGuestArr.length===0)aResponse?aResponse(-4):0;
  var WhereSql=[' ROOM_ID='+aRoomId];
  WhereSql.push(" AND CHECK_FLAG='' AND ( ")
  for(var i in aGuestArr)
  {
  if(i>0)WhereSql(' OR ')
  WhereSql.push(' ( GASTNR='+aGuestArr[i].id+' AND UNIX_TIMESTAMP(ANREISE)='+aGuestArr[i].in_time+' )' );
  }
  WhereSql.push(" ) ")
  console.log(WhereSql.join(''));
  MySql.DeleteTable(DataTable.TableGuestCheckIn,WhereSql.join(''),false,
  function(Rst){
if(Rst===false)Rst=-1;
  aResponse?aResponse(Rst):0;
  });
},


}
function GetSexName(sex)
{
if (sex||sex==="")
    {
        return "";
    }
    else if (sex.toUpperCase()==="M")
    {
        return "(男)";
    }
    else
    {
        return "(女)";
    }
}
exports.GuestModel=GuestModel;

Module层require了日期处理的公共函数和数据库表名的字符串.这就不多说了, 反而是这里响应了SQL查询的callback后, 还要继续触发回Controller传入的Response,两重callback, 不知道是不是有更优雅的实现方法呢....

现在的项目已经能run起来了

再附上runbat.bat 双击则可启动后台了.(F:\nodejs 是我安装nodejs的目录,因为没有设环境变量, 这里就直接写了.)

@echo off
cd /d %~dp0
set fpath=%~dp0
set npath=F:\nodejs
echo on
%npath%\node.exe %fpath%app.js
pause

接口的测试就不赋调用代码了, Get和Post请求都是用一般的Httpget和HttpPost格式, 即使是跨域也不须用jsonp什么的了.

 类似资料: