【NestJS系列】连接数据库及优雅地处理响应
前言
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系列】连接数据库及优雅地处理响应的更多相关文章
- Spring系列 SpringMVC的请求与数据响应
Spring系列 SpringMVC的请求与数据响应 SpringMVC的数据响应 数据响应的方式 y以下案例均部署在Tomcat上,使用浏览器来访问一个简单的success.jsp页面来实现 Suc ...
- asp.net core系列 38 WebAPI 返回类型与响应格式--必备
一.返回类型 ASP.NET Core 提供以下 Web API Action方法返回类型选项,以及说明每种返回类型的最佳适用情况: (1) 固定类型 (2) IActionResult (3) Ac ...
- React 系列 - 写出优雅的路由
前言 自前端框架风靡以来,路由一词在前端的热度与日俱增,他是几乎所有前端框架的核心功能点.不同于后端,前端的路由往往需要表达更多的业务功能,例如与菜单耦合.与标题耦合.与"面包屑" ...
- 实战SpringCloud响应式微服务系列教程(第十章)响应式RESTful服务完整代码示例
本文为实战SpringCloud响应式微服务系列教程第十章,本章给出响应式RESTful服务完整代码示例.建议没有之前基础的童鞋,先看之前的章节,章节目录放在文末. 1.搭建响应式RESTful服务. ...
- jQuery-1.9.1源码分析系列(十六)ajax——响应数据处理和api整理
ajax在得到请求响应后主要会做两个处理:获取响应数据和使用类型转化器转化数据 a.获取响应数据 获取响应数据是调用ajaxHandleResponses函数来处理. ajaxHandleRespon ...
- 【CSS3 入门教程系列】CSS3 Media Queries 实现响应式设计
在 CSS2 中,你可以为不同的媒介设备(如屏幕.打印机)指定专用的样式表,而现在借助 CSS3 的 Media Queries 特性,可以更为有效的实现这个功能.你可以为媒介类型添加某些条件,检测设 ...
- 微信开发系列----02:实现POST请求响应
继续昨天的,现在我们的微信测试成功了,可以开发实现微信的各种功能,今天主要实现微信的简单交互,比如发送语音,图片,文本等请求,网站服务器发送对应的响应. 项目GitHub地址: https://gi ...
- Effective java 系列之更优雅的关闭资源-try-with-resources
背景: 在Java编程过程中,如果打开了外部资源(文件.数据库连接.网络连接等),我们必须在这些外部资源使用完毕后,手动关闭它们.因为外部资源不由JVM管理,无法享用JVM的垃圾回收机制,如果我们不在 ...
- struts系列:返回json格式的响应
一.增加依赖库 // https://mvnrepository.com/artifact/org.apache.struts/struts2-json-plugin compile group: ' ...
- 程序员的自我修养系列(一):优雅的代码管理工具之GitHub
1.导言 代码管理是程序员经常遇到一个问题,很多童鞋将代码保存到本地硬盘,此种方法管理混乱,也存在代码丢失的风险,且版本无法控制,因此养成良好的代码管理习惯是程序员的必修课.在众多代码管理工具中笔者在 ...
随机推荐
- docker +node 部署vue项目的心路历程
最近自己做了个小项目,试着使用docker来进行发布,而其中用到了node做跨越代理,就是为了解决这个问题至少多花费了我一天时间,不说了直接进入主题吧 step 1 部署环境 1 安装 centos ...
- react中useRef的应用
何为useRef useRef是随着react函数式组件发展而来的,是react众多官方hook中的一个,调用useRef可以返回一个伴随这组件整个声明周期不发生改变的对象,这个对象常见的用途有两个: ...
- 牧云 • 主机管理助手|正式开放应用市场,梦幻联动雷池WAF等多款开源软件
0x00 前言 上个月,我司长亭开源了雷池WAF,不到三天就吸引了超过上千个师傅使用,几个交流群里,师傅们讨论的热火朝天,其中两个话题引起了我们牧云 • 主机管理助手 ( Collie ) 团队的关注 ...
- 为什么会出现 setTimeout 倒计时误差
setTimeout 倒计时误差的出现主要与 JavaScript 的事件循环机制和计时器的执行方式有关. 在 JavaScript 中,事件循环是用于管理和调度代码执行的机制.setTimeout ...
- WPF中小的技能点 1
图片圆角的处理方式 采用boder里background背景设置图片并设置对应的圆角 <Border CornerRadius="20"> < ...
- 云上使用 Stable Diffusion ,模型数据如何共享和存储
随着人工智能技术的爆发,内容生成式人工智能(AIGC)成为了当下热门领域.除了 ChatGPT 之外,文本生成图像技术更令人惊艳. Stable Diffusion,是一款开源的深度学习模型.与 Mi ...
- 基于DSP的设备振动信号的采集技术方案综述
前记 在能源领域,由于很多地方都是无人值守,设备故障检测是一个必须面对的问题.笔者通过几个行业案例了解到,由于很多设备发生故障时候会产生特定频谱的声音,所以该行业对振动监测的需求特别强烈,由于涉及到 ...
- Taurus .Net Core 微服务开源框架:Admin 插件【4-1】 - 配置管理-Kestrel【含https启用】
前言: 继上篇:Taurus .Net Core 微服务开源框架:Admin 插件[3] - 指标统计管理 本篇继续介绍下一个内容: 1.系统配置节点:App - Config 界面 界面图如下: 双 ...
- 文盘Rust -- FFI 浅尝
rust FFI 是rust与其他语言互调的桥梁,通过FFI rust 可以有效继承 C 语言的历史资产.本期通过几个例子来聊聊rust与C 语言交互的具体步骤. 场景一 调用C代码 创建工程 car ...
- Github入门教程(新版)
GitHub 的介绍与使用 GitHub 注册一个账号 直接在首页注册即可啦 要注意的是 第一项 username 别人是可见的 后面修改也会比较麻烦,所以起个好名字很重要 个人主页介绍 刚注册好的页 ...