还不会搭建 Node 服务?一文带你了解如何用 express + ts 搞定后端

前言

哈喽,小伙伴你好,我是 SuperYing前端开发全栈化趋势 卷的前端小伙伴们日益焦虑,不会搭建后端服务怎么办;不了解 node 应用怎么办;不会组织业务接口怎么办;不用怕!今天我们一起来梳理下 nodejs 框架 – express 搭建后端的全流程,一次性整明白这玩意儿。

不了解 express 的小伙伴,可以看我之前的文章《express 基础入门》

看完本文您将收获:

  1. 了解 express 后端工程搭建全流程。
  2. 了解 express 如何集成 typescript,并运行项目。
  3. 了解注解式接口开发,集成 routing-controllertypeorm
  4. 了解 typeorm 如何应用 mysql 服务。
  5. 了解 express 业务接口开发方式,明确所需要素,包括 controlelrentityservice 等。

技术准备

本文工程基于 express 框架搭建,由 typescript 提供类型支持,ORM 框架选择 typeorm,应用其特性开发使用 mysql 数据库的应用。

项目涉及的主要依赖:

  • express: express 包。
  • typescript: typescript包。
  • typeorm: typeorm 包。
  • body-parser: 用于设置 express 如何处理客户端发送的 body
  • mysql/mysql2: 底层数据库驱动程序。如果你使用的是其他数据库系统,则必须安装相应的
  • reflect-metadata: 若使用装饰器语法则必需,用于使装饰器正常工作。
  • routing-controllers: 支持以注解的形式处理请求行为,如 @Get@Post 等。

搭建过程

此过程中涉及到的命令均在 终端 执行。

mac 系统 command + 空格,搜索 teminal终端 并打开。

window 系统 win + R,输入 cmd 并回车。

打开 终端 后,cd 命令跳转到指定工作空间,就可以开始后面的操作啦。

pnpm 初始化

1. 新增项目目录,目录名为 server

# 创建项目目录
mkdir server
# 跳转到工程目录
cd server

2. 执行 pnpm 命令,初始化工程目录

pnpm init

需要全局安装 pnpm,终端执行 npm i pnpm -g 即可。

若不喜欢 pnpm,使用 npmyarn 也是可以的。

执行完成后,会在 server 根目录下生成一个最基础的 package.json 文件。

{
  "name": "server",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

到此,pnpm 初始化完成。

typescript 初始化及配置

1. 安装 typescript 依赖

pnpm add typescript -D

2. 初始化 typescript 配置

tsc --init

执行成功后,会在 server 根目录下生成一个包含默认配置的 tsconfig.json 文件。

3. 根据项目需求,精简配置

typescript 配置文件保留以下配置项:

{
  "compilerOptions": {
    "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
    "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
    "lib": ["es5", "es6"], /* Specify library files to be included in the compilation. */
    "strict": true, /* Enable all strict type-checking options. */
    "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
    "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
    "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
    "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
  }
}

注意:需要开启 experimentalDecoratorsemitDecoratorMetadata 配置,因为后续的 typeormrouting-controller 处理会用拿到 typescript装饰器特性

到此,typescript 相关处理完成。

添加 express

1. 安装 express 相关依赖

pnpm add express body-parser routing-controllers

pnpm add @types/express @types/body-parser -D

2. 添加应用入口文件

2.1 在 server 根目录下,新建 app.ts 文件,作为应用的入口文件。

app.ts 中引用 routing-controllerscreateExpressServer 函数,用于创建 express 应用实例

import { createExpressServer } from 'routing-controllers'
import { json, urlencoded } from 'body-parser'

const app = createExpressServer({
  controllers: []
})

// body 解析相关中间件
// 解析 json 格式
app.use(json())
// 解析 urlencoded body
// 会在 request 对象上挂载 body 属性,包含解析后的数据。
// 这个新的 body 对象包含 key-value 键值对,若设置 extended 为 true,则键值可以是任意累心个,否则只能是字符串或数组。
app.use(urlencoded({ extended: true }))

此时我们还没有 controllers,将在下一步实现 User 接口时添加。

2.2 启动服务,监听 3000 端口

app.ts 中添加以下代码,表示启动服务,监听 3000 端口,若启动成功则控制台打印提示信息。

app.listen(3000, () => {
  console.log(`  App is running at http://localhost:3000\n`)
  console.log('  Press CTRL-C to stop\n')
})

2.3 测试运行

因为使用 typescript 编写,若想直接运行 app.ts,需要安装 ts-node 包。

pnpm add ts-node -D

安装完成后,在 package.jsonscripts 配置处添加 start 启动命令。

"scripts": {
    "start": "ts-node app.ts"
},

保存后,控制台运行 pnpm start,打印如下内容即表示服务启动成功。

还不会搭建 Node 服务?一文带你了解如何用 express + ts 搞定后端

打开浏览器访问 http://localhost:3000

还不会搭建 Node 服务?一文带你了解如何用 express + ts 搞定后端

什么都没有?不要慌,我们还没开发接口,后续我们会实现一个 User 接口。

添加 typeorm

1. 安装 typeorm 相关依赖

pnpm add typeorm mysql reflect-metadata

注意:
后续启动服务时,若出现因本地 mysql 版本过低无法授权的问题(Client does not support authentication protocol requested by server; consider upgrading MySQL client),可将 mysql 包改为安装 mysql2,即 pnpm add typeorm mysql2 reflect-metadata.

2. 添加数据库配置

在本项目中,数据库使用 mysql,需要先在本地安装数据库环境(有线上环境就请忽略)。不清楚的小伙伴可以自行百度,资源很多。如果你恰巧使用的 mac 电脑,可以看看我之前的文章《Mac 使用 Mysql》,按步操作即可。

安装并启动了 mysql 环境,就可以开始在项目中配置数据库信息啦。

server 根目录新建 data-source.ts 文件,导出一个 DataSource 实例:

import path from 'path'
import { DataSource } from 'typeorm'

const dataSource = new DataSource({
  type: 'mysql', // 数据库类型
  host: 'localhost', // mysql 服务地址
  port: 3306, // mysql 服务启动端口
  username: 'root', // mysql 用户名
  password: 'admin0125', // mysql 密码
  database: 'zimuadmin', // 数据库
  entities: [path.join(__dirname, '/../**/*.entity.{js,ts}')], // typeorm 实体
  entityPrefix: 'zm-', // 数据库表前缀
  logging: true // 开启日志
})

export default dataSource

  • type: 数据库类型,比如我用的是 mysql
  • host: 数据库服务器地址,本地的都是 localhost
  • port: 数据库服务启动端口,默认 3306
  • username: 数据库服务登录用户名。
  • password: 数据库服务登录密码。
  • database: 指定使用的数据库名称,一个 mysql 服务可以包含多个数据库,可以在控制台执行 show databases 查询所有的数据库。zimuadmin 是我本地创建的数据库。
  • entities: 配置 typeorm 实体,src/models/*.tssrc/models 下的 ts 文件都是实体。

3. 实现业务接口

到这,我们需要安装的依赖包已经基本搞定啦。接下来,我们来实践一下,开发一个 用户管理模块

3.1 建表并初始化数据

我们按照正常的开发流程来走,先设计一下用户表结构。大家可以先想一想,用户数据会涉及到哪些属性?

mysql 控制台执行以下 sql 语句:

CREATE TABLE `zm-user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `job_no` varchar(100) NOT NULL COMMENT '工号',
  `name` varchar(100) DEFAULT NULL COMMENT '姓名',
  `sex` varchar(1) DEFAULT NULL COMMENT '性别',
  `tel` varchar(20) DEFAULT NULL COMMENT '手机号',
  `email` varchar(50) DEFAULT NULL COMMENT '邮箱',
  `address` varchar(200) DEFAULT NULL COMMENT '地址',
  `status` varchar(50) DEFAULT NULL COMMENT '状态',
  `is_super` varchar(1) DEFAULT 'N' COMMENT '是否超集管理员',
  `created_by` varchar(100) DEFAULT NULL COMMENT '创建人',
  `created_at` datetime DEFAULT NULL COMMENT '创建人',
  `updated_by` varchar(100) DEFAULT NULL COMMENT '更新人',
  `updated_at` datetime DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `zm-user_id_uindex` (`id`),
  UNIQUE KEY `zm-user_job_no_uindex` (`job_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户表'

创建了一个包括 工号姓名性别手机号 等属性的用户表,其中 id 是自增主键,job_no 唯一,且不允许为空。

接下来执行以下 sql 插入一条 张三 的数据:

insert into `zm-user` (id, job_no, name, sex, tel, email, address, status, is_super, created_by, created_at, updated_by,
                       updated_at)
values (1, '2023040100001', '张三', 'W', '13999999999', '13999999999@163.com',
        '广东省佛山市顺德区某某镇某某小区某某栋某某号', 'Active', 'N', 'root', DATE('2024-04-04 00:00:01'), 'root',
        DATE('2024-04-04 00:00:01'));

执行成功后,查询用户表可获得以下结果:

还不会搭建 Node 服务?一文带你了解如何用 express + ts 搞定后端

3.2 完善目录结构

如果一步步跟着操作过来的话,现在你的目录结构应该是这样的:

|-- server
    |-- node_modules
    |-- app.ts
    |-- data-source.ts
    |-- package.json
    |-- pnpm-lock.yaml
    |-- tsconfig.json

接下来我们调整目录结构如下:

|-- server
    |-- node_modules
    |-- src
        |-- controllers 
            |-- user.controller.ts
        |-- entities
            |-- user.entity.ts
        |-- services
            |-- user.service.ts
    |-- app.ts
    |-- data-source.ts
    |-- package.json
    |-- pnpm-lock.yaml
    |-- tsconfig.json
  • controllers: 放置 controller 层相关文件,即业务接口入口部分。
  • entities: 放置实体类文件。
  • services: 放置服务层文件。

3.2 新增实体类 entity

entities 目录下新建一个 user.entity.ts,定义 User 实体的相关属性。

/**
 * 用户实体
 */
import { Column, Entity, PrimaryColumn, PrimaryGeneratedColumn } from 'typeorm'

@Entity('user')
export class User {
  @PrimaryGeneratedColumn()
  id!: number

  @PrimaryColumn({ name: 'job_no' })
  jobNo!: string

  @Column()
  name!: string

  @Column()
  sex!: string

  @Column()
  tel!: string

  @Column()
  email!: string

  @Column()
  address!: string

  @Column({ name: 'created_by' })
  createdBy!: string

  @Column({ type: 'date', name: 'created_at' })
  createdAt!: string

  @Column({ name: 'updated_by' })
  updatedBy!: string

  @Column({ type: 'date', name: 'updated_at' })
  updatedAt!: string
}

3.3 新增服务类 service

service 目录下新建一个 user.service.ts,定义 User 相关处理逻辑,这里我们先创建一个 queryList 方法,用来查询并返回所有的用户数据及用户数。

/**
 * 用户服务类
 */
import db from '../db'
import { User } from '../entities/user'

const userRepository = db.getRepository(User)

export class UserService {
  // 查询全部用户
  async queryList() {
    return await userRepository.findAndCount()
  }
}

3.4 新增 controller

service 目录下新建一个 user.controller.ts,定义用户相关接口,这里我们先定义一个 queryListget 接口。

/**
 * 用户 controller
 */
import { Controller, Get } from 'routing-controllers'
import { UserService } from '../services/user.service'

@Controller('/user')
export class UserController {
  userService
  constructor() {
    this.userService = new UserService()
  }

  @Get('/queryList')
  queryList() {
    return this.userService.queryList()
  }
}

3.5 入口文件 app.ts

到这,我们已经完成了最基本的 用户管理模块,包含一个列表查询接口。

现在我们 pnpm start 启动服务,打开浏览器,输入 http://localhost:3000/user/queryList 来验证一下。

然而现实却给了当头一棒:

还不会搭建 Node 服务?一文带你了解如何用 express + ts 搞定后端

原来我们还没有处理入口文件,在 app.ts 中需要添加以下两步:

  1. 初始化 DataSource.
  2. UserController 添加到 createExpressServercontrollers 参数中。
import { createExpressServer } from 'routing-controllers'
import { json, urlencoded } from 'body-parser'
import 'reflect-metadata'
import ds from './data-source'
import { UserController } from './src/controllers/user.controller'

// 新增:初始化 DataSource
ds.initialize()
  .then(() => {
    console.log('Data Source has been initialized!')
  })
  .catch((e: any) => {
    console.log('Error during Data Source initialization:', e)
  })

const app = createExpressServer({
  // 新增:添加 UserController
  controllers: [UserController]
})

// body 解析相关中间件
// 解析 json 格式
app.use(json())
// 解析 urlencoded body
// 会在 request 对象上挂载 body 属性,包含解析后的数据。
// 这个新的 body 对象包含 key-value 键值对,若设置 extended 为 true,则键值可以是任意累心个,否则只能是字符串或数组。
app.use(urlencoded({ extended: true }))

app.listen(3000, () => {
  console.log(`  App is running at http://localhost:3000\n`)
  console.log('  Press CTRL-C to stop\n')
})

3.6 运行验证

关闭已有服务,重新执行 pnpm start 再次启动。

浏览器输入 http://localhost:3000/user/queryList,我们来瞅瞅效果:

还不会搭建 Node 服务?一文带你了解如何用 express + ts 搞定后端

ok,接口数据已经返回,其中数组的第 1 个元素是 用户列表,第 2 个元素是数据总数,这是 typeormfindAndCount 函数的返回结构。

规范化

到这,一个基础的 express 后端工程已经完成。但对于实际项目,除了实现业务功能外,还要考虑代码规范团队协作后期运维 等。

可以集成工具实现或配置文件(包括但不限于):

  • eslint
  • prettier
  • husky
  • commitlint
  • editorconfig
  • npmrc
  • nvmrc

由于规范化内容不是本文的重点,此处就不多占篇幅了,感兴趣的小伙伴可以前往《那些应该知道的前端规范工具》了解。

结语

好啦,以上就是搭建 express 工程的全部内容了,配套代码已上传至 GitHub。本文从空目录开始,一步步集成 typescripttypeormrouting-controllersmysql 等,直到最终实现业务模块并验证通过,旨在梳理后端工程的完整搭建过程。若您对于某个环节有疑问,欢迎评论区,一起沟通交流。

感谢阅读!愿你我共同进步,谢谢!!!

原文链接:https://juejin.cn/post/7349569626341081140 作者:是嘟老板呐

(0)
上一篇 2024年3月25日 下午4:53
下一篇 2024年3月25日 下午5:03

相关推荐

发表回复

登录后才能评论