一、先预习/复习下Node.js相关内容
1.简介
简单的说 Node.js 就是运行在服务端的 JavaScript 环境。
Node.js 是一个基于Chrome JavaScript 运行时建立的一个平台。基于Google的V8引擎,V8引擎执行Javascript的速度非常快,性能非常好。
2.安装
Windows下载安装:https://nodejs.org/en/download/
Mac下载安装:brew install node
安装ts-nodenpm install ts-node
由于是基于typescript,需安装相关依赖
npm install @types/node
npm install typescript
npm install tslint
3.创建一个Node.js应用
项目的根目录的src目录下创建一个叫 server.ts 的文件:
server.ts
import express from 'express';
const app = express();
app.get('/', (req, res) => {
res.send('Hello World');
});
app.listen(8888, () => {
var host = server.address().address;
var port = server.address().port;
console.log("应用实例,访问地址为 http://%s:%s", host, port)
});
使用ts-node执行npx ts-node ./src/server.ts
浏览器打开127.0.0.1:8888
4.路由
我们要为路由提供请求的 URL 和其他需要的 GET 及 POST 参数,随后路由需要根据这些数据来执行相应的代码。和前端路由不同的是,NodeJs路由主要是处理后端业务逻辑并且返回包含处理后数据的响应体。
// server.ts
import express from 'express';
const app = express();
// 响应get请求
app.get('/get_user', (req, res) => {
const reqQuery = {
"first_name": req.query.first_name,
"last_name": req.query.last_name
};
const resBody = reqQuery;
res.end(JSON.stringify(resBody));
});
// 响应post请求,参数为json
app.post('/list_user', (req, res) => {
let reqBody: any|string = '';
// 获取请求体数据
req.on('data', chunk => {
reqBody += chunk;
});
// 请求数据获取完成
req.on('end', () => {
reqBody = JSON.parse(reqBody || '{}');
const resBody = reqBody;
res.send(resBody);
});
});
// 对页面 abcd, abxcd, ab123cd, 等响应 GET 请求
app.get('/ab*cd', function(req, res) {
console.log("/ab*cd GET 请求");
res.send('正则匹配');
})
app.listen(8081);
执行npx ts-node ./src/server.ts
get请求
post请求
路由字符串匹配
5.上传文件 Multer
Multer是用于处理multipart/form-data的node.js中间件,主要用于上传文件。它是在busboy之上编写的,以实现最大效率。
server.ts
import express from 'express';
import fs from 'fs';
import bodyParser from 'bodyParser';
import multer from 'multer';
const app = express();
app.use(multer({
// 上传文件默认存放路径
dest: '/tmp/'
})
// 第一个参数是字段名,第二个参数是最多上传数
.array('attachment', 5));
app.post('/file_upload', (req, res) => {
const reqFile = req.files[0];
// 最终存放文件位置
const desFile = 'C://Desktop/' + reqFile.originalname;
fs.readFile( reqFile.path, (readErr, data) => {
fs.writeFile(des_file, data, function (writeErr) {
if (writeErr) {
console.log(writeErr);
} else {
resBody = {
message: 'File uploaded successfully',
filename: reqFile.originalname
};
}
console.log(resBody);
res.send(resBody);
});
});
});
app.listen(8081);
执行npx ts-node ./src/server.ts
6.cookies
server.ts
import express from 'express';
import cookieParser from 'cookie-parser';
import util from 'util';
var app = express();
// 使用cookie解析中间件
app.use(cookieParser());
app.post('/', function(req, res) {
res.send({
// inspect方法用于解析cookies
cookies: util.inspect(req.cookies),
code: 200
});
});
app.listen(8081);
执行npx ts-node ./src/server.ts
7.express框架
Express 是一个简洁而灵活的 node.js Web应用框架, 提供了一系列强大特性帮助你创建各种 Web 应用,和丰富的 HTTP 工具。
npm install express
以下几个重要的模块是需要与 express 框架一起安装的:
body-parser - node.js 中间件,用于处理 JSON, Raw, Text 和 URL 编码的数据。
cookie-parser - 这就是一个解析Cookie的工具。通过req.cookies可以取到传过来的cookie,并把它们转成对象。
multer - node.js 中间件,用于处理 enctype="multipart/form-data"(设置表单的MIME编码)的表单数据。
npm install body-parser
npm install cookie-parser
npm install multer
二、开始搭建项目结构
1.整体目录结构
2.server.ts - 服务启动入口
// 第三方模块
import bodyParser from 'body-parser';
import express from 'express';
import { NextFunction, Request, Response } from 'express'; // express 申明文件定义的类型
// 自定义配置
import systemConfig from './config';
import loadRouters from './routers/routers';
import connectDatabase from './utils/database';
let app = express();
app = loadRouters(app);
// 连接数据库
connectDatabase.then(res => {
console.log('in database: isOpenDatabase', res);
});
// 处理 post 请求的请求体,限制大小最多为 20 兆
app.use(bodyParser.urlencoded({ limit: '20mb', extended: true }));
app.use(bodyParser.json({ limit: '20mb' }));
// error handler
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
return res.sendStatus(500);
});
app.listen(systemConfig.port, () => {
console.log(`the server is start at port ${systemConfig.port}`);
});
export default app;
3.config - 定义基础配置
定义基础的数据变量和常量
例如 systemConfig.ts
import { SystemConfig } from '../types/systemConfig';
const config: SystemConfig = {
port: 8081,
database: 'mongodb://localhost:27017/test',
uploadPath: '/Users/linli/Desktop/',
jsonPath: '/Users/linli/Desktop/'
};
export default config;
4.types - 类型声明接口
用于声明数据类型
例如 systemConfig.d.ts
export interface SystemConfig {
// 服务器端口号
port: number;
// 数据库地址
database: string;
// 上传地址
uploadPath: string;
// json存放地址
jsonPath: string;
}
5.routers - 后端路由
不同的路由对应不同控制器处理方法
routers.ts 主路由
import userRouter from './user.router';
// import xxxRouter from './xxx.router';
/**
* 路由加载工厂函数
* @param app any
* @returns app
*/
const loadRouters = (app: any) => {
// 加载 用户 路由
app.use(userRouter);
return app;
};
export default loadRouters;
userRouter.ts 用户路由
import express from 'express';
import cookieParse from 'cookie-parser';
import UserController from '../controllers/user.controller';
const userRouter = express.Router();
userRouter.use(cookieParse());
userRouter.use(express.urlencoded({ extended: false }));
// 创建用户
userRouter.post('/createUser.vm', UserController.createUser);
// 删除用户
userRouter.post('/deleteUser.vm', UserController.deleteUser);
// 查询用户
userRouter.post('/getUser.vm', UserController.getUser);
// 查询用户列表
userRouter.post('/getUserList.vm', UserController.getUserList);
// 修改用户
userRouter.post('/updateUser.vm', UserController.updateUser);
export default userRouter;
6.controllers - 控制器
用于处理复杂业务逻辑
例如 user.controller.ts
import util from 'util';
import crypto from 'crypto';
import { BaseDao } from '../utils/base-dao';
import userModel from '../models/user.model';
const userDao = new BaseDao(userModel);
const UserController = {
/**
* 创建用户
* @param req 请求对象
* @param res 响应对象
*/
createUser(req: any, res: any) {
console.log('in createUser: req.body', req.body);
console.log('Cookies: ' + util.inspect(req.cookies));
// 请求体对象
let reqBody: any|string = '';
// 获取请求体数据
req.on('data', (chunk: any) => {
reqBody += chunk;
});
// 请求数据获取完成
req.on('end', () => {
// 解析请求体
reqBody = JSON.parse(reqBody || '{}');
// 数据库中创建用户
userDao.create([
{
username: reqBody.username,
password: crypto.createHash('sha256').update(reqBody.password).digest('hex')
}
], (result: any) => {
res.send(result);
});
});
},
/**
* 获取用户
* @param req 请求对象
* @param res 响应对象
*/
getUser(req: any, res: any) {
console.log('in userRouter queryUser req:', req);
// 请求体对象
let reqBody: any|string = '';
// 获取请求体数据
req.on('data', (chunk: any) => {
reqBody += chunk;
});
// 请求数据获取完成
req.on('end', () => {
// 解析请求体
reqBody = JSON.parse(reqBody || '{}');
console.log('in createUser: req.body', reqBody);
// 从数据库中查找用户
userDao.query(reqBody, (result: any) => {
res.send(result);
});
});
},
/**
* 获取用户列表
* @param req 请求对象
* @param res 响应对象
*/
getUserList(req: any, res: any) {
// 请求体对象
let reqBody: any|string = '';
// 获取请求体数据
req.on('data', (chunk: any) => {
reqBody += chunk;
});
// 请求数据获取完成
req.on('end', () => {
// 解析请求体
reqBody = JSON.parse(reqBody || '{}');
console.log('in createUser: req.body', reqBody);
// 数据库中获取用户列表
userDao.getAll((result: any) => {
res.send(result);
});
});
},
/**
* 更新对象
* @param req 请求对象
* @param res 响应对象
*/
updateUser(req: any, res: any) {
// 请求体对象
let reqBody: any|string = '';
// 获取请求体数据
req.on('data', (chunk: any) => {
reqBody += chunk;
});
// 请求数据获取完成
req.on('end', () => {
// 解析请求体
reqBody = JSON.parse(reqBody || '{}');
reqBody.password = crypto.createHash('sha256').update(reqBody.password).digest('hex');
console.log('in createUser: req.body', reqBody);
// 数据库中更新用户
userDao.update({
_id: reqBody.id
},
{
$set: reqBody
}, {}, (result: any) => {
res.send(result);
});
});
},
/**
* 删除对象
* @param req 请求对象
* @param res 响应对象
*/
deleteUser(req: any, res: any) {
// 请求体对象
let reqBody: any|string = '';
// 获取请求体数据
req.on('data', (chunk: any) => {
reqBody += chunk;
});
// 请求数据获取完成
req.on('end', () => {
// 解析请求体
reqBody = JSON.parse(reqBody || '{}');
console.log('in createUser: req.body', reqBody);
// 数据库中删除用户
userDao.delete(reqBody, (result: any) => {
res.send(result);
});
});
}
};
export default UserController;
7.util - 工具类
数据库实例封装
例如 database.ts
import mongoose from 'mongoose';
// 自定义配置
import systemConfig from '../config';
export default new Promise((resolve, reject) => {
// 连接数据库
mongoose.connect(systemConfig.database, { useCreateIndex: true, useNewUrlParser: true });
mongoose.connection.once('open', error => {
if (!error) {
console.log('数据库连接成功');
resolve(true);
} else {
console.log('数据库连接失败', error);
reject(error);
}
});
});
数据层基础方法构造函数
例如 base-dao.ts
/**
* Created by lilin on 19-11-19
*/
export class BaseDao {
model: any;
constructor(newModel: any) {
this.model = newModel;
}
/**
* 创建
* @param docs any[] 新建对象集合
* @param callback
*/
create(docs: any[], callback: any) {
this.model.create(docs, (error: any) => {
if (error) {
return callback({data: null, code: 500});
}
return callback({data: 'success', code: 200});
});
}
/**
* 查询
* @param params 查询条件
* @param callback
*/
query(conditions: any, callback: any) {
this.model.findOne(conditions, (error: any, result: any) => {
if (error) {
return callback({data: null, code: 500});
}
return callback({data: result, code: 200});
});
}
/**
* 查询所有数据
* @param callback
*/
getAll(callback: any) {
this.model.find({}, (error: any, result: any) => {
if (error) {
return callback({data: null, code: 500});
}
return callback({data: result, code: 200});
});
}
/**
* 删除
* @param params 删除条件
* @param callback
*/
delete(conditions: any, callback: any) {
this.model.remove(conditions, (error: any) => {
if (error) {
return callback({data: null, code: 500});
}
return callback({data: 'success', code: 200});
});
}
/**
* 更新
* @param conditions 更新条件
* @param doc 更新后的对象
* @param options 更新选项
* @param callback 回调
*/
update(conditions: any, doc: any, options: any, callback: any) {
this.model.update(conditions, doc, options, (error: any) => {
if (error) {
return callback({data: null, code: 500});
}
return callback({data: 'success', code: 200});
});
}
}
8.models - mongoose 模型
Models 是从 Schema 编译来的构造函数。 它们的实例就代表着可以从数据库保存和读取的 documents。 从数据库创建和读取 document 的所有操作都是通过 model 进行的。
不了解mongodb和mongoose的同学可以看看官网文档,本篇文章主要讲架构
例如 user.model.ts
import { Schema, model } from 'mongoose';
const userSchema = new Schema({
username: {
type: String,
unique: true,
required: true
},
password: {
type: String,
required: true
}
});
const userModel = model('user', userSchema);
export default userModel;
9. package.json - npm依赖和构建脚本
{
"name": "template-node-ts",
"version": "1.0.0",
"scripts": {
"serve": "ts-node src/server.ts",
"dev": "ts-node-dev src/server.ts"
},
"dependencies": {
"@types/cookie-parser": "^1.4.2",
"@types/express": "^4.17.2",
"@types/mongoose": "^5.5.32",
"@types/multer": "^1.3.10",
"cookie-parser": "^1.4.4",
"express": "^4.17.1",
"mongoose": "^5.7.11",
"multer": "^1.4.2"
},
"devDependencies": {
"@types/jest": "^24.0.13",
"@types/node": "^12.0.2",
"@types/supertest": "^2.0.7",
"jest": "^24.8.0",
"supertest": "^4.0.2",
"ts-jest": "^24.0.2",
"ts-node": "^8.5.2",
"ts-node-dev": "^1.0.0-pre.39",
"tslint": "^5.17.0",
"typescript": "^3.7.2"
}
}
10.tsconfig.ts - ts配置
{
"compilerOptions": {
/* Basic Options */
"target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
// ts-node 目前不支持es2015的的模块机制
// https://github.com/TypeStrong/ts-node/issues/313#issuecomment-343698812
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
/* Strict Type-Checking Options */
"strict": true, /* Enable all strict type-checking options. */
"noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
/* Module Resolution Options */
"moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
"baseUrl": ".", /* Base directory to resolve non-absolute module names. */
"paths": {
"*": [
"node_modules/*",
"src/types/*"
]
},
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
/* Experimental Options */
"experimentalDecorators": true /* Enables experimental support for ES7 decorators. */
},
"exclude": ["node_modules"]
}
三、项目演示
搭建好项目结构后,运行npx node-ts ./src/server.ts
也可以通过tsc
打包后,在生成的dist目录下执行node server.js
创建用户
查询用户
删除用户
更新用户
四、总结
本篇文章主要讲解typescript在Node.js原型工程中的项目架构,如果有不明确或者有错误的地方还请万能的网友指点,如果觉得文章对你有帮助,希望点个赞鼓励下哦,最后,在这特殊的时期祝愿大家平平安安、身体健康,闲的没事可以多逛逛掘金,不要着急出门,武汉加油,中国加油!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。