React+Redux+Ant Design+TypeScript 电子商务实战-服务端应用 01 服务端初始搭建

服务端技术栈介绍

初始化服务器端项目

# 创建项目文件夹
mkdir ecommerce-end
cd ecommerce-end
# 生成 package.json
npm init -y

创建初始目录结构

├─ config # 存放应用配置文件
├─ controllers # 存放 MongoDB 数据管理方法
├─ helpers # 存放辅助函数
├─ models # 存放 MongoDB 连接、Model(mongoose 概念)
├─ pem # 存放支付宝密钥
├─ routes # 路由接口配置
├─ validator # 存放路由接口前置校验回调
├─ .env # dotenv 环境变量
├─ app.js # 应用入口文件
├─ .gitignore # git 忽略文件配置
├─ 接口文档.md
└─ package.json

安装依赖

npm i express express-jwt express-validator cors body-parser cookie-parser morgan formidable mongoose mongoose-unique-validator nodemon config dotenv cross-env jsonwebtoken order-id uuid lodash alipay-sdk
  • 服务器相关
    • express:基于 Node.js 的 web 应用开发框架
    • express-jwt:用于解析 JWT 的中间件
    • express-validator:校验中间件
    • cors:CORS 中间件
    • body-parser:HTTP 请求体解析中间件
    • cookie-parser:请求体 Cookie 解析中间件
    • morgan:HTTP 请求日志中间件
    • formidable:解析表单数据的工具,尤其是文件上传
  • 数据库相关
    • mongoose:在 Node.js 异步环境下对 MongoDB 进行便捷操作的对象模型工具
    • mongoose-unique-validator:mongoose 插件,为 Mongoose Schemoa 中的唯一标识属性添加预保存验证
  • 应用相关
    • nodemon:自动检测并重启应用的工具
    • config:Node.js 应用配置工具
    • dotenv.env 文件设置环境变量
    • cross-env:跨平台使用脚本设置环境变量的工具
  • 安全权限相关
    • jsonwebtoken:JWT 生成工具
    • order-id:唯一订单 id 生成器
    • uuid:UUID 生成器,生成用于密码加密的盐(Salt)
  • 其它工具

忽略 node_module(.gitignore):

node_modules

创建 web 服务器

配置环境变量 - 服务器监听端口

dotenv 将环境变量从 .env 文件加载到 process.env 中。

# .env
# 服务启动监听端口
APP_PORT=80

创建 web 服务和配置中间件

// app.js
const express = require('express')
const cors = require('cors')
const morgan = require('morgan')
const bodyParse = require('body-parse')
const cookieParser = require('cookie-parser')

// 创建 web 服务器
const app = express()

// 添加中间件
// 开启 CORS
app.use(cors())
// morgan 预定义的 dev 格式的请求日志
app.use(morgan('dev'))
// 解析 form 请求
app.use(bodyParser.json())
// 使用 qs 库解析 URL 编码数据请求
app.use(bodyParser.urlencoded({ extended: true }))
// 解析请求体中的 cookie
app.use(cookieParser())

// 请求接口
app.get('/', (req, res) => {
  res.send('请求成功')
})

const APP_PORT = process.env.APP_PORT || 80

app.listen(APP_PORT, () => {
  console.log(`服务器启动成功,监听 ${APP_PORT} 端口`)
})

配置启动脚本

编程方式加载 dotenv,需要在应用程序中尽早 require 并配置。

// 在 app.js 的顶部加载 dotenv
// `config` 会读取 `.env` 文件,解析内容,将其分配给 `process.env`。
require('dotenv').config()

也可以使用命令行方式预加载 dotevn,使用 --require-r 命令行选项预加载 dotenv,这样做就不需要在应用程序代码中加载 require('dotenv')

package.json

"scripts": {
  "start": "nodemon -r dotenv/config app.js"
},

运行 npm start

访问 http://localhost/,终端会打印请求日志:

GET / 200 2.413 ms - 12GET /favicon.ico 404 1.086 ms - 150

创建本地数据库

安装工具

安装 MongoDB 和可视化管理工具 Robo 3T

启动 MongoDB

# 启动 MongoDB 服务
# 管理员身份打开命令行工具
# `MongoDB` 是安装 MongoDB 时默认的服务名称
net start MongoDB

创建数据库

创建本地 MongoDB 连接

在这里插入图片描述

这里使用管理员身份连接本地 MongoDB,只需设置连接名称 Name 即可。

点击 Connect 连接后,右键左侧的连接 - Create Database,创建数据库,命名为 ecommerce

配置数据库连接信息

node-config 模块介绍

node-config(npm 名是 config) 模块用于管理应用的配置,根据环境变量 NODE_ENV 获取对应环境下的配置,也可以在配置中使用环境变量。

配置文件可以是 .json/.json5/.js 文件或其它类型的文件。

JSON5 是对 JSON 的扩展,可以在文件中像 JS 一样编写 JSON 对象和注释。

更多参考 Configuration Files

node-config 会自动获取根目录下 config(默认) 文件夹中的配置文件,合并生成对应环境下的配置信息:

  • default.json:默认配置参数,其它文件可能会覆盖这些参数
    • 覆盖是在每个参数的基础上完成,不同与对象引用的合并
    • node-config 运行时会先匹配 default.json,后续匹配的文件覆盖它,如果不存在 default.json,则继续匹配后面的文件
  • <NODE_ENV>.json:env 环境配置,覆盖默认配置,根据 NODE_ENV 使用同名的配置文件
    • NODE_ENV=production:使用 product.json 文件
    • NODE_ENV=development:使用 development.json 文件
    • NODE_ENV=demo:使用 demo.json文件
    • 当未配置 NODE_ENV,node-config 默认其值为 development
  • custom-environment-variables.json:使用环境变量的配置,优先级仅低于命令行配置

例如:

# .env
APP_PORT=80
DB_NAME=mydatabase
// config/default.json
{
  "Customer": {
    "appConfig": {
      "lang": "简体中文",
      "theme": "default",
      "port": 1000
    },
    "dbConfig": {
      "host": "localhost"
    }
  }
}
// config/development.json
{
  "Customer": {
    "appConfig": {
      "title": "开发环境",
      "theme": "blue"
    }
  }
}
// config/production.json
{
  "Customer": {
    "appConfig": {
      "title": "生产环境",
      "theme": "green"
    },
    "dbConfig": {
      "host": "127.0.0.1"
    }
  }
}
// config/custom-environment-variables.json
{
  "Customer": {
    "appConfig": {
      "port": "APP_PORT"
    },
    "dbConfig": {
      "name": "DB_NAME"
    }
  }
}

require('config').get('Customer') 结果:

// 开发环境
{
  appConfig: { lang: '简体中文', theme: 'blue', port: '80', title: '开发环境' },
  dbConfig: { host: 'localhost', name: 'mydatabase' }
}
// 生产环境
{
  appConfig: { lang: '简体中文', theme: 'green', port: '80', title: '生产环境' },
  dbConfig: { host: '127.0.0.1', name: 'mydatabase' }
}

配置项目数据库信息

# .env
# 服务启动监听端口
APP_PORT=80

# 本地数据库连接信息
# 连接地址
DB_HOST=localhost
# 数据库名称
DB_NAME=ecommerce
# 用户名(默认为空)
DB_USER=
# 密码(默认为空)
DB_PASS=
# 端口(默认27017)
DB_PORT=27017

// config\custom-environment-variables.json
{
  "dbConfig": {
    "host": "DB_HOST",
    "name": "DB_NAME",
    "user": "DB_USER",
    "pass": "DB_PASS",
    "port": "DB_PORT"
  }
}

连接数据库

Mongoose 介绍

Mongoose 可以连接 MongoDB 数据库。

var mongoose = require('mongoose')
// var db = mongoose.connect('mongodb://<host>:<port>/<databaseName>'[, options])
// 示例
var db = mongoose.connect('mongodb://localhost:27017/mydatabase', {
  user,
  pass,

  // 下面的参数的作用是使用新版的功能替换已弃用(即将在未来版本中删除)的功能
  // 如果不设置,就会在终端输出警告提示,并不影响使用
  // 详细参考 https://mongoosejs.com/docs/deprecations.html
  useNewUrlParser: true, // URL 字符串解析器
  useUnifiedTopology: true // 服务器发现和监视引擎
})

Mongoose 一切始于 Schema,每个 schema 都会映射到一个 MongoDB collection,定义并约束这个 collection 里 document 的构成。

// 创建一个 Schema
var blogSchema = new mongoose.Schema({
  title: String, // 约束类型为 String
  date: {
    type: Date, // 使用 type 属性指定约束类型
    default: Date.now // 默认值
  },
  comments: [{ title: String, date: Date }]
})

将 Schema 编译成 Model,Model 是用来创建 document 实例的 Class,也可以用来查询 documents。

// 编译一个 Model

// 第一个参数是 Model 名称,是对应 collection 名称的`单数`形式(不区分大小写)
// MongoDB 会自动找到名称是 Model 名字`复数`形式的 collection(匹配全小写)
// 例如 Blog 就是对应数据库中 blogs 这个 collection 的 Model 名称;Category 对应 categories

// 第二个参数就是依据的 Schema

// `.model()` 就是对 Schema 做了拷贝(生成了 model)
// 要确保在调用 `.model()` 之前把所有需要的东西都加进 Schema 里

// 注意:直到 Model 使用的数据库连接打开后,才可以操作 collection
// 如果 collection 不存在,保存 save 操作会自动创建这个 collection
// 如果 collection 不存在,查询 find 操作会返回 `[]`
var BlogModel = mongoose.model('Blog', blogSchema)

// 创建一个 document 实例
var blog = new BlogModel({ title: '测试文章'})
// 保存文章
blog.save()

通过 Model 的静态方法 find 查询:

// 立即执行查询:传入 error-first 回调函数参数
BlogModel.find((error, data) => {
  console.log(data)
})
// 不立即执行查询:不传入回调函数参数
// 返回一个 Query 查询实例
var query = BlogModel.find()
// 调用 Query 对象的执行查询方法:回调方式
query.exec((error, data) => {
  console.log(data)
})
// 调用 Query 对象的执行查询方法:Promise 方式
query.exec().then(console.log)

更多文档请参考 mongoose 英文原版文档

创建数据库连接

// models\connect.js
const mongoose = require('mongoose')
const config = require('config')

const { host, port, user, pass, name } = config.get('dbConfig')

mongoose
  .connect(`mongodb://${host}:${port}/${name}`, {
    useNewUrlParser: true, // URL 字符串解析器
    useCreateIndex: true, // 定义索引的函数使用 `createIndex` 方法替换废弃的 `ensureIndex`
    useUnifiedTopology: true, // 服务器发现和监视引擎
    useFindAndModify: false, // 使用 MongoDB 的 `findOneAndUpdate` 方法替换过早的 `findAndModify` 方法
    user,
    pass
  })
  .then(() => console.log('数据库连接成功'))
  .catch(() => console.log('数据库连接失败'))

在启动 web 服务前引入这个文件:

// app.js
const express = require('express')
const cors = require('cors')
const morgan = require('morgan')
const bodyParse = require('body-parse')
const cookieParser = require('cookie-parser')

// 连接数据库
require('./models/connect')

// 创建 web 服务器
const app = express()

// 添加中间件
// 开启 CORS
app.use(cors())
// morgan 预定义的 dev 格式的请求日志
app.use(morgan('dev'))
// 解析 form 请求
app.use(bodyParser.json())
// 使用 qs 库解析 URL 编码数据请求
app.use(bodyParser.urlencoded({ extended: true }))
// 解析请求体中的 cookie
app.use(cookieParser())

// 请求接口
app.get('/', (req, res) => {
  res.send('请求成功')
})

const APP_PORT = process.env.APP_PORT || 80

app.listen(APP_PORT, () => {
  console.log(`服务器启动成功,监听 ${APP_PORT} 端口`)
})

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值