前言

Node作为一门后端语言,当然也可以连接数据库,为前端提供CURD接口

我们以mysql为例,自行安装mysql

TypeORM

TypeORM 是一个ORM框架,它可以运行在 NodeJS、Browser、Cordova、PhoneGap、Ionic、React Native、Expo 和 Electron 平台上,可以与 TypeScript 和 JavaScript一起使用。 它的目标是始终支持最新的 JavaScript 特性并提供额外的特性以帮助你开发任何使用数据库的(不管是只有几张表的小型应用还是拥有多数据库的大型企业应用)应用程序。

TypeORM作为TypeScript中最成熟的对象关系映射器,可以很好的与Nest框架集成使用。

安装依赖

npm install --save @nestjs/typeorm typeorm mysql2

新建数据库

CREATE DATABASE nanjiu
DEFAULT CHARACTER SET = 'utf8mb4';

新建一个nanjiu数据库

连接数据库

数据库建好之后,我们就可以使用typeorm来连接数据库并建立映射关系了

// dbConfig.ts
// 数据库配置
export function dbConfig() {
return {
type: 'mysql', // 数据库类型
host: '127.0.0.1', // 数据库地址
port: 3306, // 端口
username: 'root', // 用户名
password: '123456', // 密码
database: 'nanjiu', // 数据库名
entities: [__dirname + '/../**/*.entity{.ts,.js}'], // 实体类
synchronize: true, // 自动创建表
autoLoadEntities: true, // 自动加载实体类
} as DbConfig
}

需要在app.module.ts中进行注册

@Module({
imports: [
NanjiuModule, UserModule, InfoModule,
TypeOrmModule.forRoot(dbConfig() as any)
],
controllers: [AppController],
providers: [AppService],
})

定义实体

实体是一个映射到数据库表的类,使用@Entity装饰器来定义

// user.entry.ts
import { Column, Entity, PrimaryGeneratedColumn } from "typeorm"; @Entity('user') // 表名
export class User { @PrimaryGeneratedColumn() // 自增主键
id: number; @Column() // 字段
name: string;
}

基本实体由列和关系组成,每个实体必须有一个主列。

每个实体都必须在连接配置中注册:

entities: [__dirname + '/../**/*.entity{.ts,.js}'], // 实体类

关联实体

实体定义后需要在module中导入并关联

@Module({
imports: [TypeOrmModule.forFeature([User])],
controllers: [UserController],
providers: [UserService]
})

当你做完这一步之后你会发现数据库里已经根据你刚刚定义的实体建好了表

这是因为刚刚数据库配置那里开启了synchronize: true 自动创建表

CURD接口

数据库准备准备工作完成后,我们就可以来写接口了

controller控制器中定义接口path

// user.controller.ts
import { CreateUserDto } from './dto/create-user.dto';
export class UserController {
constructor(
private readonly userService: UserService,
) {} @Post('addUser')
create(@Body() createUserDto: CreateUserDto) {
// 添加用户
return this.userService.add(createUserDto);
}
}

新建DTO数据验证器

import { Injectable } from "@nestjs/common";
import { IsNotEmpty, IsString } from "class-validator"; // 引入验证器
@Injectable()
export class CreateUserDto {
@IsString({ message: '用户名必须是字符串'}) // 验证是否是字符串
@IsNotEmpty({ message: '用户名不能为空'}) // 验证是否为空
name: string; // 用户名
}

dto一般用来做参数验证

注册全局DTO验证管道

// main.ts
import { ValidationPipe } from '@nestjs/common'; app.useGlobalPipes(new ValidationPipe()) // 全局验证管道

service逻辑处理,入库操作

// user.service.ts
import { Injectable } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { User } from './entities/user.entity';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm'; @Injectable()
export class UserService {
constructor(
// 使用 @InjectRepository(User) 注入实数据库实体
@InjectRepository(User)
private readonly userRepository: Repository<User>
) {} async add(createUserDto: CreateUserDto) {
// 添加用户,更多操作参考 TypeORM 文档
const res = await this.userRepository.save(createUserDto);
return res
}
}

调用接口

查看数据库

调用完接口,此时数据库中会新增一条数据

响应结果处理

从上面的响应结果来看并不规范,只是简单的返回了数据库查询结果,并且当系统发生异常错误时,如果我们没有手动处理异常,所有的异常都会进入到nest内置的异常处理层,它返回的信息格式如下:

{
"statusCode": 500,
"message": "Internal server error"
}

比如我们往user库中插入相同的name,但name设置了唯一性,所以这时会抛出错误,如果我们不处理返回给前端就是上面那种信息,这样前端同学看到就会很蒙,根本不知道为啥报错

所以我们要做的就是将响应格式化处理

在nest中,一般是在service中处理异常,如果有异常,直接抛出错误,由过滤器捕获,统一格式返回,如果成功,service把结果返回,controller直接return结果即可,由拦截器捕获,统一格式返回

失败:过滤器统一处理

成功:拦截器统一处理

异常拦截器

为了更加优雅地处理异常,我们可以创建一个异常过滤器,它主要用来捕获作为HttpException类实例的异常。

异常抛出封装:

// httpStatus.service.ts
import { Injectable, HttpException, HttpStatus, NestInterceptor } from '@nestjs/common' @Injectable()
export class HttpStatusError {
static fail(error, status = HttpStatus.BAD_REQUEST) {
throw new HttpException({statusCode: status, message: '请求失败', error}, status)
}
}

抛出异常:

// group.service.ts
// ...
import { HttpStatusError } from '../utils/httpStatus.service' @Injectable()
export class GroupService {
constructor(
@InjectRepository(Group)
private groupRepository: Repository<Group>,
@InjectRepository(Template)
private templateRepository: Repository<Template>,
) {}
// todo: 添加分组
async create(createGroupDto: CreateGroupDto) {
const data = this.groupRepository.create(createGroupDto);
const group = await this.groupRepository.findOne({ where: { name: createGroupDto.name } });
if (group) {
return HttpStatusError.fail('该分组已存在');
}
try {
const res = await this.groupRepository.save(data, { reload: true });
return res;
} catch (error) {
return HttpStatusError.fail(error);
}
}
}

异常拦截器封装:

import {
ArgumentsHost,
Catch,
ExceptionFilter,
HttpException,
} from '@nestjs/common'; @Catch()
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const request = ctx.getRequest(); const status = exception.getStatus();
const exceptionRes: any = exception.getResponse();
const { error, message } = exceptionRes; const msgLog = {
status,
message,
error,
path: request.url,
timestamp: new Date().toLocaleString(),
}; response.status(status).json(msgLog);
}
}

使用:

 app.useGlobalFilters(new HttpExceptionFilter()); // 全局异常过滤器

请求:

这样报错信息就能够一目了然,简单实用的话可以直接抛出异常就可以,然后在抛出异常的地方给出详细信息。

全局响应拦截器

那成功的响应应该如何优雅地处理呢?

Interceptor拦截器

这里我们可以使用Interceptor拦截器,给成功响应按固定格式返回

import { Injectable, HttpException, HttpStatus, NestInterceptor, ExecutionContext,CallHandler } from '@nestjs/common'
import { Observable } from 'rxjs'
import { map } from 'rxjs/operators' @Injectable()
export class HttpStatusSuccess implements NestInterceptor{
intercept(context: ExecutionContext, next: CallHandler) :Observable<any> {
return next.handle().pipe(map(data => {
return {
statusCode: HttpStatus.OK,
message: '请求成功',
data
}
}))
}
}

使用:

 app.useGlobalInterceptors(new HttpStatusSuccess()); // 全局拦截器请求成功

请求:

【NestJS系列】连接数据库及优雅地处理响应的更多相关文章

  1. Spring系列 SpringMVC的请求与数据响应

    Spring系列 SpringMVC的请求与数据响应 SpringMVC的数据响应 数据响应的方式 y以下案例均部署在Tomcat上,使用浏览器来访问一个简单的success.jsp页面来实现 Suc ...

  2. asp.net core系列 38 WebAPI 返回类型与响应格式--必备

    一.返回类型 ASP.NET Core 提供以下 Web API Action方法返回类型选项,以及说明每种返回类型的最佳适用情况: (1) 固定类型 (2) IActionResult (3) Ac ...

  3. React 系列 - 写出优雅的路由

    前言 自前端框架风靡以来,路由一词在前端的热度与日俱增,他是几乎所有前端框架的核心功能点.不同于后端,前端的路由往往需要表达更多的业务功能,例如与菜单耦合.与标题耦合.与"面包屑" ...

  4. 实战SpringCloud响应式微服务系列教程(第十章)响应式RESTful服务完整代码示例

    本文为实战SpringCloud响应式微服务系列教程第十章,本章给出响应式RESTful服务完整代码示例.建议没有之前基础的童鞋,先看之前的章节,章节目录放在文末. 1.搭建响应式RESTful服务. ...

  5. jQuery-1.9.1源码分析系列(十六)ajax——响应数据处理和api整理

    ajax在得到请求响应后主要会做两个处理:获取响应数据和使用类型转化器转化数据 a.获取响应数据 获取响应数据是调用ajaxHandleResponses函数来处理. ajaxHandleRespon ...

  6. 【CSS3 入门教程系列】CSS3 Media Queries 实现响应式设计

    在 CSS2 中,你可以为不同的媒介设备(如屏幕.打印机)指定专用的样式表,而现在借助 CSS3 的 Media Queries 特性,可以更为有效的实现这个功能.你可以为媒介类型添加某些条件,检测设 ...

  7. 微信开发系列----02:实现POST请求响应

    继续昨天的,现在我们的微信测试成功了,可以开发实现微信的各种功能,今天主要实现微信的简单交互,比如发送语音,图片,文本等请求,网站服务器发送对应的响应. 项目GitHub地址:  https://gi ...

  8. Effective java 系列之更优雅的关闭资源-try-with-resources

    背景: 在Java编程过程中,如果打开了外部资源(文件.数据库连接.网络连接等),我们必须在这些外部资源使用完毕后,手动关闭它们.因为外部资源不由JVM管理,无法享用JVM的垃圾回收机制,如果我们不在 ...

  9. struts系列:返回json格式的响应

    一.增加依赖库 // https://mvnrepository.com/artifact/org.apache.struts/struts2-json-plugin compile group: ' ...

  10. 程序员的自我修养系列(一):优雅的代码管理工具之GitHub

    1.导言 代码管理是程序员经常遇到一个问题,很多童鞋将代码保存到本地硬盘,此种方法管理混乱,也存在代码丢失的风险,且版本无法控制,因此养成良好的代码管理习惯是程序员的必修课.在众多代码管理工具中笔者在 ...

随机推荐

  1. uni-app 打包发行

    1.云端 发行-原生App-云打包 2.离线 运行-原生App本地打包-生成本地打包资源,如果提示安装依赖包,安装即可 注意:项目的AppID不能为空,请在该项目下的manifest.json中重新获 ...

  2. HTML渲染机制

    一直写页面但是很少对一些较深的运行机制的了解,这次趁休假查了一些相关的资料加上个人理解,记录一下关于html渲染的整个过程,也加深一下自己对html渲染的理解 一.先借一张图来看看html的整个加载过 ...

  3. Python连接es笔记二之查询方式汇总

    本文首发于公众号:Hunter后端 原文链接:Python连接es笔记二之查询方式汇总 上一节除了介绍使用 Python 连接 es,还有最简单的 query() 方法,这一节介绍一下几种其他的查询方 ...

  4. Intellij IDEA最新激活码,适合2022,2023和所有版本,永久更新

    分享一下 IntelliJ IDEA 2023.1 最新激活注册码,破解教程如下,可免费永久激活,亲测有效,下面是详细文档哦~ 申明:本教程 IntelliJ IDEA 破解补丁.激活码均收集于网络, ...

  5. Python modbus_tk 库源码分析

    modbus_tk 源代码分析 前言 modbus_tcp 协议是工业项目中常见的一种基于 TCP/IP 协议的设备数据交互协议. 作为 TCP/IP 协议的上层协议,modbus_tcp 协议涉及到 ...

  6. Go语言中的结构体:灵活性与可扩展性的重要角色

    1. 引言 结构体是Go语言中重要且灵活的概念之一.结构体的使用使得我们可以定义自己的数据类型,并将不同类型的字段组合在一起,实现更灵活的数据结构.本文旨在深入介绍Go语言中的结构体,揭示其重要性和灵 ...

  7. 逍遥自在学C语言 | 多级指针探秘

    前言 多级指针在C语言中是一种特殊的指针类型,它可以指向其他指针的指针. 通过多级指针,我们可以间接地访问或修改存储在内存中的数据. 在本文中,我们将讨论多级指针的概念.使用方法.使用场景以及常见错误 ...

  8. PostgreSQL 新手入门指引

    自从MySQL被Oracle收购以后,PostgreSQL 逐渐成为开源关系型数据库的首选. 本文介绍PostgreSQL的安装和基本用法,供初次使用者上手.以下内容基于Debian操作系统,其他操作 ...

  9. HCL实验:3.两台PC通过路由器交换机PING通

    拓扑图 路由器配置网关 PC1 ping PC2, PC3

  10. .net core提示502.5错误

    最近给WindowsServer2012服务器部署.Net Core项目,部署后一直显示502.5错误,具体如下: 网上找了一大堆解决办法都行不通,最后在stackoverflow中找到说是缺少一个补 ...