前言

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. vue全家桶进阶之路27:Vue.js 3.0的下载和安装

    使用脚手架vue-cli创建vue3项目,创建前需要准备以下: 1.node.js环境 见:https://www.cnblogs.com/beichengshiqiao/p/17251233.htm ...

  2. R EnhancedVolcano 绘制火山图

    火山图是用于差异表达分析结果可视化的一种有效方法.今天,我们来介绍一个用于增强火山图绘制的强大 R 包:EnhancedVolcano ,该包拥有强大的绘图功能,用户可以简单的通过设置颜色.形状.大小 ...

  3. “AI Earth”人工智能创新挑战赛:助力精准气象和海洋预测Baseline[1]、NetCDF4使用教学、Xarray 使用教学,针对气象领域.nc文件读取处理

    1."AI Earth"人工智能创新挑战赛:助力精准气象和海洋预测Baseline[1].NetCDF4使用教学.Xarray 使用教学,针对气象领域.nc文件读取处理 比赛官网: ...

  4. 一篇文章带你入门HBase

    本文已收录至Github,推荐阅读 Java随想录 微信公众号:Java随想录 目录 HBase特性 Hadoop的限制 基本概念 NameSpace Table RowKey Column Time ...

  5. 如何在矩池云上安装和使用 Stata

    Stata是一款功能强大的统计分析软件,本文提供了如何在矩池云安装使用 Stata,以及如何在 Jupyter 中使用 Stata 的简要教程. 安装 Stata 时需要确保按照官方指南进行操作,St ...

  6. 浅谈OpenCV的多对象匹配图像的实现,以及如何匹配透明控件,不规则图像

    浅谈OpenCV的多对象匹配透明图像的实现,以及如何匹配半透明控件 引子 OpenCV提供的templateMatch只负责将(相关性等)计算出来,并不会直接提供目标的对应坐标,一般来说我们直接遍历最 ...

  7. Python3.7源码编译

    1.下载Python3.7.0源码 git clone https://github.com/python/cpython.gitgit checkout v3.7.0 wget https://ww ...

  8. iOS select标签适配去掉iOS默认select样式

    iOS端对select标签有独特的适配,如何取消这些默认样式呢 css样式表 加上 1 select { 2 -webkit-appearance: none; 3 } 博客同步更新:地址

  9. python台历代码--涉及知识点为Excel表格合并等操作

    from openpyxl.styles import Alignment, PatternFill, Fontfrom openpyxl.utils import get_column_letter ...

  10. WinUI(WASDK)使用MediaPipe检查人体姿态关键点

    前言 之前有用这个MediaPipe.NET .NET包装库搞了手势识别,丰富了稚晖君的ElectronBot机器人的第三方上位机软件的功能,MediaPipe作为谷歌开源的机器视觉库,功能很丰富了, ...