【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.导言 代码管理是程序员经常遇到一个问题,很多童鞋将代码保存到本地硬盘,此种方法管理混乱,也存在代码丢失的风险,且版本无法控制,因此养成良好的代码管理习惯是程序员的必修课.在众多代码管理工具中笔者在 ...
随机推荐
- 聊聊Seata分布式解决方案AT模式的实现原理
什么是Seata分布式事务解决方案 Seata是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务.为用户提供了AT.TCC.SAGA和XA事务模式,为用户打造一站式的分布式解决 ...
- LeetCode 周赛 346(2023/05/21)仅 68 人 AK 的最短路问题
本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 提问. LeetCode 单周赛第 345 场 · 体验一题多解的算法之美 单周赛 345 概览 T1. 删除子串后 ...
- AcWing 243. 一个简单的整数问题2-(区间修改,区间查询)
给定一个长度为 N 的数列 A,以及 M 条指令,每条指令可能是以下两种之一: C l r d,表示把 A[l],A[l+1],-,A[r]都加上 d. Q l r,表示询问数列中第 l∼r个数的和. ...
- 你以为搞个流水线每天跑,团队就在使用CI/CD实践了?
在实践中,很多团队对于DevOps 流水线没有很透彻的理解,要不就创建一大堆流水线,要不就一个流水线通吃.实际上,流水线的设计和写代码一样,需要基于"业务场景"进行一定的设计编排, ...
- GPT3:人工智能时代的新型语言模型
目录 GPT-3:人工智能时代的新型语言模型 随着人工智能技术的不断发展,自然语言处理领域也迎来了新的里程碑.GPT-3 是当前最具代表性的语言模型之一,它具有如下特点: GPT-3 是一种全新的语言 ...
- AI室内设计:提升效率、消除沟通障碍,满足客户需求
前言 免费AI绘图工具:https://www.topgpt.one 随着人工智能(AI)技术的不断发展,室内设计行业也开始受益于这一技术的应用.其中,AI绘画工具在室内设计中的应用正日益受到关注.这 ...
- Python运维开发之路《模块》
一.模块 1. 模块初识 模块定义:模块(module),通常也被称为库(lib,library),是一个包含所有你定义的函数和变量的文件,其后缀名是.py.模块可以被别的程序引入,以使用该模块中 ...
- Git存储
Git还提供了一个贮藏的功能.如果你某个分支开发过程中,这个分支的内容是要在本月月底上线的,但是生产上已经出现了一个重大bug,需要你立马去修复.你在分支开发的内容已经开发一部分了,工作区有内容是不能 ...
- Abaqus添加初始缺陷
主要介绍通过施加节点位移的方法 步骤一: 复制model,新建Step,static linear perturbation Tools->Analytical Field 定义场函数,例如:A ...
- C语言基础--逻辑判断和循环
目录 一.储存标识符 1.auto 2.register 3.static 4.const 二.运算符 1.逻辑运算符 2.位运算符 3.运算符 4.三元运算符 三.选择结构 1.if判断 1.1 i ...