MEAN Stack






4.89/5 (8投票s)
MongoDB, Express, AngularJS, Node.js 缩写为 MEAN - 这些开发工具都使用 Javascript。在这个示例中,我们将使用 MSSQL Server 代替 MongoDb。
通过这个应用程序示例,我们可以创建一个新用户,显示所有用户,修改用户数据,以及通过使用 AngularJS 从前端使用 Express 构建的 API 删除用户。
Components
- MSSql - SQL 数据库
- Express - NodeJS 框架
- Angular - 用于前端的 JavaScript 框架
- Node.js - JavaScript 执行环境 (服务器)
依赖项
强烈建议您查看之前的文章以了解本文
让我们在 MSSql 服务器中创建一个数据库,用于存储用户数据,该数据库将由我们的应用程序操作。 创建数据库后,通过使用该数据库执行以下查询。
CREATE TABLE [dbo].[User](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](250) NULL,
[Email] [nvarchar](250) NULL,
[Phone] [nvarchar](50) NULL,
CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, _
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
这将创建一个名为 user
的新表。 之后,我们需要创建一些存储过程用于 SQL 操作,复制下面的脚本并将其粘贴到 MSSql 查询窗口中执行。
CREATE PROCEDURE [dbo].[GetUsers]
-- Add the parameters for the stored procedure here
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
SELECT * FROM [dbo].[User]
END
GO
CREATE PROCEDURE [dbo].[GetUserById]
@Id Int
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
SELECT * FROM [dbo].[User] WHERE Id = @Id
END
GO
CREATE PROCEDURE [dbo].[PutUser]
-- Add the parameters for the stored procedure here
@Id INT,
@Name NVarchar(250),
@Email NVarchar(250),
@Phone NVarchar(50)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
Update [dbo].[User]
SET [Name] = @Name,[Email] = @Email,[Phone] = @Phone
WHERE [Id] = @Id
END
GO
CREATE PROCEDURE [dbo].[SetUser]
-- Add the parameters for the stored procedure here
@Name NVarchar(250),
@Email NVarchar(250),
@Phone NVarchar(50)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
INSERT INTO [dbo].[User]([Name],[Email],[Phone])
VALUES(@Name,@Email,@Phone)
END
GO
CREATE PROCEDURE [dbo].[DeleteUser]
-- Add the parameters for the stored procedure here
@Id Int
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
DELETE FROM [dbo].[User]
WHERE [Id] = @Id
END
--Exec DeleteUser 1
GO
我们已经完成了数据库工作。 让我们开始应用程序开发计划。 从我们之前的应用程序示例开始。
从 GitHub 下载它,然后使用 Visual Studio 2017 打开应用程序。我们需要安装另外两个软件包才能满足我们的要求。
mssql
- 用于 Node.js 的 Microsoft SQL Server 客户端body-parser
- Node.js body 解析中间件
服务器端
包安装
右键单击项目,转到 > 在此处打开命令提示符。 运行此命令以安装 mssql
。
npm install mssql
运行此命令以安装 body-parser
。
npm install body-parser
完成此安装后,我们需要将它们添加到我们的节点服务器。 在这里,我们通过启用添加了它们。
var bodyParser = require("body-parser");
然后,我们必须将其用于我们的应用程序。
//Body Parser Middleware
app.use(bodyParser.json()
app.use(bodyParser.urlencoded({ extended: true }));
在此示例中,操作将通过使用 Express 路由的 API 执行。 让我们开始创建 API 的过程。
API
让我们创建数据服务以在数据库中执行操作。 添加一个公共 dbService.js 文件来处理请求,如下图所示
打开新添加的 js 文件,然后添加此行
var mssql = require('mssql');
这意味着我们通过 require()
函数来加载 mssql 模块,从而在新函数中加载源代码。
之后,我们添加数据库服务器连接配置
var dbConfig = {
user: "sa",
password: "sa@12345",
server: "DESKTOP-80DEJMQ",
database: "dbNode",
pool: {
max: 10,
min: 0,
idleTimeoutMillis: 30000
}
};
正如我们所看到的,max
池是 10
,min
是 0
,以及关闭未使用的连接之前的超时时间(以毫秒为单位),这是默认值。
获取有关池的更多详细信息:https://github.com/coopernurse/node-pool
var executeQuery = function (sql, res) {
const conn = new mssql.ConnectionPool(dbConfig);
conn.connect().then(function () {
const req = new mssql.Request(conn);
req.query(sql).then(function (data) {
res(data);
}).catch(function (err) {
res(null, err);
})
}).catch(function (err) {
res(null, err);
})
}
连接
const conn = new mssql.ConnectionPool(dbConfig);
我们正在使用 connectionpool
创建 SQL 连接对象。
请求
const req = new mssql.Request(conn);
然后,我们使用全局连接池执行请求。
获取有关连接的更多详细信息:https://npmjs.net.cn/package/mssql#connections-1
最后,我们正在导出 module
以供另一个 module
调用。
module.exports = {
executeQuery
}
让我们使用 Express 路由器创建一个特定的数据服务。 创建一个新的 JS 文件,然后将下面的代码片段添加到新添加的文件中。
var express = require('express');
var router = express.Router();
var dbService = require('../dbService');
//GET API
router.get("/api/user/getAll", function (req, res) {
var query = "GetUsers";
dbService.executeQuery(query, function (data, err) {
if (err) {
throw err;
} else {
res.send(data.recordset);
}
res.end();
});
});
// GET API
router.get("/api/user/getUser/:id", function (req, res) {
var query = "[GetUserById] " + parseInt(req.params.id) + "";
dbService.executeQuery(query, function (data, err) {
if (err) {
throw err;
} else {
res.send(data.recordset);
}
res.end();
});
});
//POST API
router.post("/api/user/setUser", function (req, res) {
var query = "[SetUser] '" + req.body.Name + "', '" +
req.body.Email + "', '" + req.body.Phone + "'";
dbService.executeQuery(query, function (data, err) {
if (err) {
throw err;
} else {
res.send(data.recordset);
}
res.end();
});
});
//PUT API
router.put("/api/user/putUser", function (req, res) {
var query = "[PutUser] " + parseInt(req.body.Id) + ", '" +
req.body.Name + "','" + req.body.Email + "', '" + req.body.Phone + "'";
dbService.executeQuery(query, function (data, err) {
if (err) {
throw err;
} else {
res.send(data.recordset);
}
res.end();
});
});
//DELETE API
router.delete("/api/user/deleteUser/:id", function (req, res) {
var query = "[DeleteUser] " + parseInt(req.params.id) + "";
dbService.executeQuery(query, function (data, err) {
if (err) {
throw err;
} else {
res.send(data.recordset);
}
res.end();
});
});
module.exports = router;
完成所有这些操作后,我们需要通过 node 服务器中的 app.use()
函数将其作为中间件启用。
//Router Middleware
app.use('/', require('./data/userService/userDataService'));
此外,我们通过启用跨域资源共享 (CORS) 来授予其他用户代理访问权限。
//CORS Middleware
app.use(function (req, res, next) {
//Enabling CORS
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT");
res.header("Access-Control-Allow-Headers",
"Origin, X-Requested-With, contentType,Content-Type, Accept, Authorization");
next();
});
最后,这是 Node 服务器的概述
'use strict';
//var http = require('http');
var bodyParser = require("body-parser");
var path = require('path');
var express = require('express');
var app = express();
var port = process.env.port || 3000;
//Body Parser Middleware
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
//Serve Static Files
app.use(express.static(path.join(__dirname, 'app')));
app.use(express.static(path.join(__dirname, 'public')));
//Router Middleware
app.use('/', require('./data/userService/userDataService'));
//CORS Middleware
app.use(function (req, res, next) {
//Enabling CORS
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT");
res.header("Access-Control-Allow-Headers", "Origin,
X-Requested-With, contentType,Content-Type, Accept, Authorization");
next();
});
app.get('/*', function (req, res) {
res.sendFile(path.resolve('layout.html'));
});
app.get('/*', function (req, res) {
res.render('error');
});
var server = app.listen(port, function () {
console.log('Node server is running on port..' + port);
});
客户端
我们需要创建用户界面来操作数据库中的数据。 首先,我们需要为特定模块创建文件夹,如下所示
如您所见,我们创建了一个带有 HTML 页面的 AngularJS 控制器。
Html 视图
<div class="container-fluid">
<div class="row">
<div class="col-sm-4">
<h3>Add New User</h3>
<form name="frmUser" novalidate>
<input type="hidden" ng-model="userModel.Id" name="uid" />
<div class="form-group">
<label for="uname" class="control-label">User Name</label>
<input type="text" class="form-control"
ng-model="userModel.Name" name="uname" placeholder="" required />
<span class="error" ng-show="(frmUser.$dirty||submitted) &&
frmUser.uname.$error.required">Customer name is Required</span>
</div>
<div class="form-group">
<label for="email" class="control-label">E-mail</label>
<input type="email" class="form-control"
ng-model="userModel.Email" name="email"
placeholder="" required />
<span class="error" ng-show="(frmUser.$dirty ||submitted) &&
frmUser.email.$error.required">EmailId is Required!</span>
<span class="error" ng-show="(frmUser.$dirty ||submitted) &&
frmUser.$error.email">Invalid EmailId!</span>
</div>
<div class="form-group">
<label for="phone" class="control-label">Phone</label>
<input type="text" class="form-control"
ng-model="userModel.Phone" name="phone" placeholder="" />
</div>
<div class="form-group">
<button type="submit" class="btn btn-danger"
ng-click="reset()">Reset</button>
<button type="submit" class="btn btn-primary"
ng-click="saveUser()" ng-disabled="frmUser.$invalid"
ng-If="userModel.Id == 0">
Create
</button>
<button type="submit" class="btn btn-success"
ng-click="updateUser()" ng-disabled="frmUser.$invalid"
ng-If="userModel.Id > 0">
Update
</button>
</div>
</form>
<span class="warning">{{resmessage}}</span>
</div>
<div class="col-sm-8">
<h3>All User</h3>
<table style="width:100%" class="table table-striped">
<tr>
<th>Sr.</th>
<th>Name</th>
<th>Email</th>
<th>Phone</th>
<th>Option</th>
</tr>
<tr ng-repeat="item in ListUser">
<td>{{ $index+1 }}</td>
<td>{{ item.Name }}</td>
<td>{{ item.Email }}</td>
<td>{{ item.Phone }}</td>
<td>
<a href="#" ng-click="getUser(item)"
title="Edit Record" class="btn btn-primary btn-xs pull-right">
Edit
</a>
<a href="#" ng-click="deleteUser(item)"
title="Delete Record" class="btn btn-danger btn-xs pull-right">
Delete
</a>
</td>
</tr>
</table>
</div>
</div>
</div>
AngularJS 控制器
在我们的 AngularJS 控制器中,我们必须使用 $http
服务与 API 通信。 使用的方法
$http.get
:获取数据$http.post
:发布新数据$http.put
:更新现有数据$http.delete
:删除现有数据
有关 $http 服务 的更多信息,请参见此处。
templatingApp.controller('UserController',
['$scope', '$http', function ($scope, $http) {
$scope.title = "All User";
$scope.ListUser = null;
$scope.userModel = {};
$scope.userModel.Id = 0;
getallData();
//******=========Get All User=========******
function getallData() {
$http({
method: 'GET',
url: '/api/user/getAll/'
}).then(function (response) {
$scope.ListUser = response.data;
}, function (error) {
console.log(error);
});
};
//******=========Get Single User=========******
$scope.getUser = function (user) {
$http({
method: 'GET',
url: '/api/user/getUser/' + parseInt(user.Id)
}).then(function (response) {
$scope.userModel = response.data[0];
}, function (error) {
console.log(error);
});
};
//******=========Save User=========******
$scope.saveUser = function () {
$http({
method: 'POST',
url: '/api/user/setUser/',
data: $scope.userModel
}).then(function (response) {
showNotif("Data Saved")
$scope.reset();
getallData();
}, function (error) {
console.log(error);
});
};
//******=========Update User=========******
$scope.updateUser = function () {
$http({
method: 'PUT',
url: '/api/user/putUser/',
data: $scope.userModel
}).then(function (response) {
showNotif("Data Updated")
$scope.reset();
getallData();
}, function (error) {
console.log(error);
});
};
//******=========Delete User=========******
$scope.deleteUser = function (user) {
var IsConf = confirm('You are about to delete ' +
user.Name + '. Are you sure?');
if (IsConf) {
$http({
method: 'DELETE',
url: '/api/user/deleteUser/' + parseInt(user.Id)
}).then(function (response) {
showNotif("Data Deleted")
$scope.reset();
getallData();
}, function (error) {
console.log(error);
});
}
};
//******=========Clear Form=========******
$scope.reset = function () {
var msg = "Form Cleared";
$scope.userModel = {};
$scope.userModel.Id = 0;
showNotif(msg)
};
}]);
发布应用程序
让我们转到 gulp
修改以最终获取 publish
文件。
gulp.task('publish', function () {
gulp.src('layout.html')
.pipe(gulp.dest(paths.publish));
gulp.src('package.json')
.pipe(gulp.dest(paths.publish));
gulp.src('server.js')
.pipe(gulp.dest(paths.publish));
gulp.src('app/**/*')
.pipe(gulp.dest(paths.publish + 'app'));
gulp.src('public/**/*')
.pipe(gulp.dest(paths.publish + 'public'));
gulp.src('data/**/*')
.pipe(gulp.dest(paths.publish + 'data'));
gulp.src('bin/**/*')
.pipe(gulp.dest(paths.publish + 'bin'));
});
转到 Visual Studio 中的任务资源管理器,如下图所示
运行该任务,这会将我们所有的应用程序文件复制到已发布的文件夹。
转到 Publish 文件夹
在此处打开命令提示符(Shift + 鼠标右键),然后键入 nodemon
。 我们正在使用 nodemon
启动我们的应用程序。 如果我们的应用程序有任何更改,nodemon
将自动重启该应用程序。
现在打开浏览器,键入 URL:https://:3000。
输出
希望这能有所帮助。:)
历史
- 2018 年 2 月 21 日:初始版本